Initial commit.

This commit is contained in:
Saleem Edah-Tally
2025-06-28 17:40:42 +02:00
commit ef6f25ef27
52 changed files with 8156 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.5)
project(MinimalUtilities)
find_package(wxWidgets COMPONENTS base core CONFIG REQUIRED)
add_library(minutils STATIC
ConfigEditorPopup.cpp
MiscTools.cpp
PopupTransientWindow.cpp
TimeredStatusBar.cpp
XClientData.hpp
)
target_link_libraries(minutils
${wxWidgets_LIBRARIES}
)

View File

@@ -0,0 +1,123 @@
/*
* File: ConfigEditorPopup.cpp
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on 4 mars 2017, 19:06
*/
#include "ConfigEditorPopup.h"
#include "MiscTools.h"
ConfigEditorPopup::ConfigEditorPopup ( wxWindow * parent, wxFileConfig* config )
{
m_owner = parent;
m_config = config;
}
ConfigEditorPopup::~ConfigEditorPopup() = default;
PopupTransientWindow* ConfigEditorPopup::CreatePopup()
{
wxASSERT_MSG ( ( m_config != nullptr ),_T("CONFIG IS nullptr") );
m_popup = new PopupTransientWindow ( m_owner );
m_pan = new wxPanel ( m_popup );
m_flxsz = new wxFlexGridSizer ( 0, 2, 0, 0 );
m_pan->SetSizer ( m_flxsz );
m_flxsz->AddGrowableCol ( 1 );
m_popup->Bind ( wxEVT_DESTROY, &ConfigEditorPopup::OnPopupDestroy, this );
return m_popup;
}
wxCheckBox* ConfigEditorPopup::AddCheckBox ( const wxString& label, const wxString& configPath )
{
wxASSERT_MSG ( ( m_config != nullptr ),_T("CONFIG IS nullptr") );
wxString * cPath = new wxString ( configPath );
wxStaticText * lbl = new wxStaticText ( m_pan, wxID_ANY, label );
m_flxsz->Add ( lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 0 );
wxCheckBox * cb = new wxCheckBox ( m_pan, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCHK_2STATE );
m_flxsz->Add ( cb, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 0 );
cb->SetValue ( m_config->ReadBool ( configPath, false ) );
cb->SetClientData ( cPath );
cb->Bind ( wxEVT_DESTROY, &ConfigEditorPopup::OnControlDestroy, this );
return cb;
}
wxSpinCtrl* ConfigEditorPopup::AddSpinCtrl ( const wxString& label, const wxString& configPath )
{
wxASSERT_MSG ( ( m_config != nullptr ),_T("CONFIG IS nullptr") );
wxString * cPath = new wxString ( configPath );
wxStaticText * lbl = new wxStaticText ( m_pan, wxID_ANY, label );
m_flxsz->Add ( lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxGROW | wxALL, 0 );
wxSpinCtrl * spn = new wxSpinCtrl ( m_pan, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS | wxALIGN_RIGHT, -100, 100 );
m_flxsz->Add ( spn, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 0 );
spn->SetValue ( ( int ) m_config->ReadLong ( configPath, 0 ) );
spn->SetClientData ( cPath );
spn->Bind ( wxEVT_DESTROY, &ConfigEditorPopup::OnControlDestroy, this );
return spn;
}
wxTextCtrl* ConfigEditorPopup::AddTextCtrl ( const wxString& label, const wxString& configPath )
{
wxASSERT_MSG ( ( m_config != nullptr ),_T("CONFIG IS nullptr") );
wxString * cPath = new wxString ( configPath );
wxStaticText * lbl = new wxStaticText ( m_pan, wxID_ANY, label );
m_flxsz->Add ( lbl, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxGROW | wxALL, 0 );
wxTextCtrl * txt = new wxTextCtrl ( m_pan, wxID_ANY );
m_flxsz->Add ( txt, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 0 );
txt->SetValue ( m_config->Read ( configPath, wxEmptyString ) );
txt->SetClientData ( cPath );
txt->Bind ( wxEVT_DESTROY, &ConfigEditorPopup::OnControlDestroy, this );
return txt;
}
void ConfigEditorPopup::OnControlDestroy ( wxWindowDestroyEvent& evt )
{
//cout << "ConfigEditorPopup::OnControlDestroy" << endl;
evt.Skip();
wxControl * ctrl = static_cast<wxControl*> ( evt.GetEventObject() );
if ( !ctrl ) return;
const wxString className ( ctrl->GetClassInfo()->GetClassName() );
const wxString * cPath = static_cast<wxString*> ( ctrl->GetClientData() );
if ( className ==_T("wxCheckBox") )
{
wxCheckBox * cb = static_cast<wxCheckBox*> ( evt.GetEventObject() );
m_config->Write ( *cPath, cb->GetValue() );
}
if ( className ==_T("wxSpinCtrl") )
{
wxSpinCtrl * spn = static_cast<wxSpinCtrl*> ( evt.GetEventObject() );
m_config->Write ( *cPath, spn->GetValue() );
}
if ( className ==_T("wxTextCtrl") )
{
wxTextCtrl * txt = static_cast<wxTextCtrl*> ( evt.GetEventObject() );
if ( txt->IsEmpty() )
{
m_config->DeleteEntry ( *cPath, true );
}
else
{
m_config->Write ( *cPath, txt->GetValue() );
}
}
m_config->Flush();
delete cPath;
}
void ConfigEditorPopup::OnPopupDestroy ( wxWindowDestroyEvent& evt )
{
//cout << "ConfigEditorPopup::OnPopupDestroy" << endl;
evt.Skip();
}
void ConfigEditorPopup::ShowPopup()
{
m_pan->GetSizer()->SetSizeHints ( m_pan );
MiscTools::ShowTransientPopup ( m_popup, m_pan, m_pan->GetSize().GetWidth(), m_pan->GetSize().GetHeight() );
}

View File

@@ -0,0 +1,46 @@
/*
* File: ConfigEditorPopup.h
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on 4 mars 2017, 19:06
*/
#ifndef CONFIGEDITORPOPUP_H
#define CONFIGEDITORPOPUP_H
#include <wx/wx.h>
#include <wx/config.h>
#include "PopupTransientWindow.h"
#include <wx/spinctrl.h>
/**
* Edits wxConfig keys using check boxes, text and spin controls, with supplied
* paths. When a control is created, it reads the values. When it is destroyed,
* it saves back the value.
*/
class ConfigEditorPopup
{
public:
ConfigEditorPopup ( wxWindow * parent, wxConfig * config );
virtual ~ConfigEditorPopup();
PopupTransientWindow* CreatePopup();
void ShowPopup();
wxCheckBox* AddCheckBox ( const wxString& label, const wxString& configPath );
wxSpinCtrl* AddSpinCtrl ( const wxString& label, const wxString& configPath );
wxTextCtrl * AddTextCtrl ( const wxString& label, const wxString& configPath );
private:
wxConfig * m_config = nullptr;
wxWeakRef<wxWindow> m_owner = nullptr;
wxFlexGridSizer * m_flxsz = nullptr;
PopupTransientWindow * m_popup = nullptr;
wxPanel * m_pan = nullptr;
void OnControlDestroy ( wxWindowDestroyEvent& evt );
void OnPopupDestroy ( wxWindowDestroyEvent& evt );
};
#endif /* CONFIGEDITORPOPUP_H */

View File

@@ -0,0 +1,132 @@
/*
* File: MiscTools.cpp
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on 4 mars 2017, 11:40
*/
#include "MiscTools.h"
#include <wx/notifmsg.h>
#include <wx/msgdlg.h>
MiscTools::MiscTools()
{
}
MiscTools::~MiscTools()
{
}
/*
* Under this... thing called Wayland, GetPosition() returns (0, 0)!
* Use "GDK_BACKEND=x11".
*/
void MiscTools::SaveSizePos(wxConfig* config, wxWindow* wind, const wxString& pathPrefix)
{
wxASSERT_MSG ( ( config != nullptr ),_T("config IS nullptr") );
wxASSERT_MSG ( ( wind != nullptr ),_T("wind IS nullptr") );
config->Write ( pathPrefix +_T("/Width"), wind->GetSize().GetWidth() );
config->Write ( pathPrefix +_T("/Height"), wind->GetSize().GetHeight() );
config->Write ( pathPrefix +_T("/X"), wind->GetPosition().x );
config->Write ( pathPrefix +_T("/Y"), wind->GetPosition().y );
config->Flush();
}
void MiscTools::RestoreSizePos ( wxConfig* config, wxWindow* wind, const wxString& pathPrefix )
{
wxASSERT_MSG ( ( config != nullptr ),_T("config IS nullptr") );
wxASSERT_MSG ( ( wind != nullptr ),_T("wind IS nullptr") );
long w = 0, h = 0;
config->Read ( pathPrefix +_T("/Width"), &w );
config->Read ( pathPrefix +_T("/Height"), &h );
if ( w && h )
{
wind->SetSize ( w, h );
}
wxScreenDC dc;
const int screenWidth = dc.GetSize().GetWidth();
const int screenHeight = dc.GetSize().GetHeight();
if (screenWidth && screenHeight)
{
long x = 0, y = 0;
bool res = config->Read ( pathPrefix +_T("/X"), &x );
res = config->Read ( pathPrefix +_T("/Y"), &y );
if ( !res )
{
wind->Centre();
return;
}
wind->SetPosition ( wxPoint ( x, y ) );
}
}
void MiscTools::ShowTransientPopup ( wxPopupTransientWindow* p, wxWindow* content,
const int width, const int height )
{
wxASSERT_MSG ( ( p != nullptr ),_T("p IS nullptr") );
wxASSERT_MSG ( ( content != nullptr ),_T("content IS nullptr") );
wxBoxSizer * sz = new wxBoxSizer ( wxVERTICAL );
p->SetSizer ( sz );
int popupWidth = width;
int popupHeight = height;
if ( width < 1 )
popupWidth = content->GetSize().GetWidth();
if ( height < 1 )
popupHeight = content->GetSize().GetHeight();
p->SetSize ( wxSize ( popupWidth, popupHeight ) );
sz->Add ( content, 0, wxGROW | wxALL );
sz->Layout();
/*
* Under Wayland, screen size is invalid (0, 0) with wxScreenDC.
* wxVideoMode obtained from wxApp doesn't help, it's even worse.
* Using GDK_BACKEND="x11" fixes the placement issue with wxScreenDC,
* but not with wxVideoMode.
*/
wxScreenDC dc;
const int screenWidth = dc.GetSize().GetWidth();
const int screenHeight = dc.GetSize().GetHeight();
const wxPoint mousePos = wxGetMousePosition();
wxPoint dest ( mousePos.x, mousePos.y );
if (screenWidth && screenHeight)
{
if ( mousePos.x > ( screenWidth - popupWidth ) ) dest.x = ( screenWidth - popupWidth );
if ( mousePos.y > ( screenHeight - popupHeight ) ) dest.y = ( screenHeight - popupHeight );
if ( popupWidth > screenWidth ) dest.x = 0;
if ( popupHeight > screenHeight ) dest.y = 0;
}
p->SetPosition ( dest );
p->Popup();
}
void MiscTools::MessageBox ( const wxString& msg, const bool notify )
{
wxApp * app = static_cast<wxApp*> ( wxApp::GetInstance() );
if ( !notify )
{
wxMessageBox ( msg, app->GetAppName(), wxOK, app->GetTopWindow() );
}
else
{
wxNotificationMessage notifMsg ( app->GetAppName(), msg, app->GetTopWindow() );
notifMsg.Show();
}
}
wxTextValidator* MiscTools::MakeFileNameValidator ( bool excludeSpace )
{
wxTextValidator * tval = new wxTextValidator ( wxFILTER_EXCLUDE_CHAR_LIST );
const wxString xcl = wxFileName::GetForbiddenChars();
wxArrayString arr;
for ( unsigned short i = 0; i < xcl.Length(); i++ )
{
arr.Add ( xcl.GetChar ( i ) );
}
if ( excludeSpace ) arr.Add (_T(" ") );
arr.Add ( wxFileName::GetPathSeparator() );
tval->SetExcludes ( arr );
return tval;
}

View File

@@ -0,0 +1,60 @@
/*
* File: MiscTools.h
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on 4 mars 2017, 11:40
*/
#ifndef MISCTOOLS_H
#define MISCTOOLS_H
#include <wx/wx.h>
#include <wx/config.h>
#include <wx/popupwin.h>
/**
* Miscellaneous static functions.
*/
class MiscTools
{
public:
MiscTools();
virtual ~MiscTools();
/**
* Saves size and position of a wxWindow.
*/
static void SaveSizePos ( wxConfig * config, wxWindow * wind, const wxString& pathPrefix );
/**
* Restores size and position of a wxWindow.
*/
static void RestoreSizePos ( wxConfig * config, wxWindow * wind, const wxString& pathPrefix );
/**
* Shows a transient popup at mouse cursor.
* Position the popup relative to screen edges and popup dimensions,
* if possible.
*/
static void ShowTransientPopup ( wxPopupTransientWindow * p, wxWindow* content,
const int width = 0, const int height = 0 );
/**
* Shows a message as a modal dialog or as a notification.
*/
static void MessageBox ( const wxString& msg, const bool notify = false );
/**
* Creates a validator excluding file name forbidden characters, path
* separator and optionally space character.
*/
static wxTextValidator* MakeFileNameValidator ( bool excludeSpace = true );
private:
};
#endif /* MISCTOOLS_H */

View File

@@ -0,0 +1,29 @@
/*
* File: PopupTransientWindow.cpp
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on 3 mars 2017, 19:45
*/
#include "PopupTransientWindow.h"
IMPLEMENT_CLASS ( PopupTransientWindow, wxPopupTransientWindow )
PopupTransientWindow::PopupTransientWindow()
: wxPopupTransientWindow()
{}
PopupTransientWindow::PopupTransientWindow ( wxWindow* parent, int flags )
: wxPopupTransientWindow ( parent, flags )
{}
PopupTransientWindow::~PopupTransientWindow()
{}
void PopupTransientWindow::Dismiss()
{
Destroy();
}

View File

@@ -0,0 +1,33 @@
/*
* File: PopupTransientWindow.h
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on 3 mars 2017, 19:45
*/
#ifndef POPUPTRANSIENTWINDOW_H
#define POPUPTRANSIENTWINDOW_H
#include <wx/wx.h>
#include <wx/popupwin.h>
/** No further functionality provided here on top of wxPopupTransientWindow.\n
* Just calls Destroy() on dismiss.
*/
class PopupTransientWindow : public wxPopupTransientWindow
{
DECLARE_CLASS ( PopupTransientWindow )
public:
PopupTransientWindow();
PopupTransientWindow ( wxWindow *parent, int flags = wxBORDER_NONE );
virtual ~PopupTransientWindow();
void Dismiss() override;
private:
};
#endif /* POPUPTRANSIENTWINDOW_H */

View File

@@ -0,0 +1,58 @@
/*
* File: TimeredStatusBar.cpp
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on April 22, 2018, 3:55 PM
*/
#include "TimeredStatusBar.h"
TimeredStatusBar::TimeredStatusBar ( wxWindow * parent)
: wxStatusBar ( parent, wxID_ANY )
{
m_numFields = 3;
/* We use default reasonable widths for CAPS and NUM. */
const int widths[3] = {-1, 70, 70};
SetFieldsCount ( m_numFields, widths );
m_timer.Stop();
m_timer.SetOwner ( this );
Bind ( wxEVT_TIMER, &TimeredStatusBar::OnTimer, this );
Bind ( wxEVT_IDLE, &TimeredStatusBar::OnIdle, this );
}
TimeredStatusBar::~TimeredStatusBar()
{
}
void TimeredStatusBar::SetTransientText ( const wxString& text, int duration )
{
wxStatusBar::SetStatusText ( text, 0 );
m_timer.Start ( duration, wxTIMER_ONE_SHOT );
}
void TimeredStatusBar::OnTimer ( wxTimerEvent& evt )
{
wxStatusBar::SetStatusText ( wxEmptyString, 0 );
}
void TimeredStatusBar::OnIdle ( wxIdleEvent& evt )
{
if ( wxGetKeyState ( WXK_NUMLOCK ) )
{
SetStatusText (_("NUM"), m_numFields - 2 );
}
else
{
SetStatusText ( wxEmptyString, m_numFields - 2 );
}
if ( wxGetKeyState ( WXK_CAPITAL ) )
{
SetStatusText (_("CAPS"), m_numFields - 1 );
}
else
{
SetStatusText ( wxEmptyString, m_numFields - 1 );
}
}

View File

@@ -0,0 +1,38 @@
/*
* File: TimeredStatusBar.h
* Author: Saleem EDAH-TALLY - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem EDAH-TALLY - © 2017
*
* Created on April 22, 2018, 3:55 PM
*/
#ifndef TIMEREDSTATUSBAR_H
#define TIMEREDSTATUSBAR_H
#include <wx/wx.h>
#include <wx/timer.h>
/**
* We want to show a transient message.\n
* The widget show also CAPS and NUM status.\n
*/
class TimeredStatusBar : public wxStatusBar
{
public:
TimeredStatusBar ( wxWindow * parent );
virtual ~TimeredStatusBar();
/**
* Called by the application to display 'text' transiently.
*/
void SetTransientText ( const wxString& text, int duration = 3000);
void OnIdle ( wxIdleEvent& evt );
private:
uint m_numFields = 3;
wxTimer m_timer;
void OnTimer ( wxTimerEvent& evt );
};
#endif /* TIMEREDSTATUSBAR_H */

View File

@@ -0,0 +1,35 @@
/*
* File: XClientData.hpp
* Author: Saleem Edah-Tally - nmset@yandex.com
* License: CeCILL-C
* Copyright Saleem Edah-Tally - © 2024
*
* Created on ?
*/
#ifndef XCLIENTDATA_H
#define XCLIENTDATA_H
#include <wx/wx.h>
/**
* For the available scanner list.
*/
class XClientData : public wxClientData
{
public :
XClientData ( const wxVariant& data ) : wxClientData()
{
m_data = data;
}
virtual ~XClientData() {};
wxVariant GetData() const
{
return m_data;
}
private:
wxVariant m_data;
};
#endif // XCLIENTDATA_H