diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ec30cb..0c956a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,9 +13,13 @@ include_directories(${CMAKE_CURRENT_LIST_DIR} Resources/InsaneWidget Resources/Utilities Resources/InsaneWidget/UI + Resources/StampWidget + Resources/StampWidget/UI + Resources/UI/S7) add_subdirectory(Resources/Utilities) +add_subdirectory(Resources/StampWidget) add_subdirectory(Resources/InsaneWidget) add_executable(s7 @@ -25,6 +29,6 @@ add_executable(s7 install(TARGETS s7 RUNTIME DESTINATION bin) -target_link_libraries(s7 minutils insanewidget +target_link_libraries(s7 insanewidget ${wxWidgets_LIBRARIES} ) diff --git a/README.md b/README.md index c62aab7..cff1034 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,10 @@ This is a simple scanning application with these goals: - full page scan - known number of pages to scan - double-sided handling - - multiple output file format: PNG, JPEG, TIFF, PNM and PDF. + - multiple output file format: PNG, JPEG, TIFF, PNM and PDF + - apply an optional stamp on each page. -It is based on [libinsane](https://gitlab.gnome.org/World/OpenPaperwork/libinsane) and written with [wxWidgets](https://wxwidgets.org). +It is based on [libinsane](https://gitlab.gnome.org/World/OpenPaperwork/libinsane) and [wxWidgets](https://wxwidgets.org). ![S7_01](S7_01.png) @@ -22,6 +23,7 @@ Inputs: - the scanner and its minimal parameters (source, mode, resolution) - page size - output file format. + - an optional stamp text Right click on the 'New' label to specify the number of faces and whether double-sided scanning is needed. diff --git a/Resources/InsaneWidget/CMakeLists.txt b/Resources/InsaneWidget/CMakeLists.txt index 31fff91..8bb6658 100644 --- a/Resources/InsaneWidget/CMakeLists.txt +++ b/Resources/InsaneWidget/CMakeLists.txt @@ -9,23 +9,24 @@ find_package(LibInsane REQUIRED) find_package(PoDoFo REQUIRED) find_package(Paper REQUIRED) - include_directories(${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/UI + ${CMAKE_CURRENT_LIST_DIR}/../StampWidget + ${CMAKE_CURRENT_LIST_DIR}/../StampWidget/UI ${CMAKE_CURRENT_LIST_DIR}/../Utilities) - + add_library(insanewidget STATIC UI/InsaneWidget.cpp UI/ScannerWidget.cpp - Common.h + DefsInsaneWidget.h XInsaneWidget.cpp XScannerWidget.cpp InsaneWorker.cpp PixelToImageWriter.cpp PixelToPdfWriter.cpp) -target_link_libraries(insanewidget minutils +target_link_libraries(insanewidget minutils stampwidget ${wxWidgets_LIBRARIES} ${LIBINSANE_LIBRARIES} ${PODOFO_LIBRARIES} diff --git a/Resources/InsaneWidget/Common.h b/Resources/InsaneWidget/DefsInsaneWidget.h similarity index 75% rename from Resources/InsaneWidget/Common.h rename to Resources/InsaneWidget/DefsInsaneWidget.h index d5f1ee8..0b85a4d 100644 --- a/Resources/InsaneWidget/Common.h +++ b/Resources/InsaneWidget/DefsInsaneWidget.h @@ -1,14 +1,14 @@ // /* -// * File: Common.h +// * File: DefsInsaneWidget.h // * Author: Saleem Edah-Tally - nmset@yandex.com // * License : CeCILL-C // * Copyright Saleem Edah-Tally - © 2025 // * -// * Created on 27 06 2025, 20:34 +// * Created on 08 07 2025, 20:44 // */ -#ifndef COMMON_H -#define COMMON_H +#ifndef DEFSINSANEWIDGET_H +#define DEFSINSANEWIDGET_H #include #include @@ -27,4 +27,4 @@ static void UpdateExtensionsMap() Extensions[PNM] = "pnm"; } -#endif // COMMON_H +#endif // DEFSINSANEWIDGET_H diff --git a/Resources/InsaneWidget/InsaneWorker.cpp b/Resources/InsaneWidget/InsaneWorker.cpp index 7a06519..ef4674e 100644 --- a/Resources/InsaneWidget/InsaneWorker.cpp +++ b/Resources/InsaneWidget/InsaneWorker.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -273,7 +272,8 @@ bool InsaneWorker::ConfigureDevice(const std::string& deviceId, * Sounds weird but needed. */ lis_set_option(m_sourceItem, OPT_NAME_SOURCE, source.c_str()); - lis_set_option(m_sourceItem, OPT_NAME_RESOLUTION, to_string(resolution).c_str()); + if (resolution > 0) // No resolution with v4l devices. + lis_set_option(m_sourceItem, OPT_NAME_RESOLUTION, to_string(resolution).c_str()); pair br; if (GetBottomRight(br)) { diff --git a/Resources/InsaneWidget/PixelToImageWriter.cpp b/Resources/InsaneWidget/PixelToImageWriter.cpp index 852ef9f..59c2a14 100644 --- a/Resources/InsaneWidget/PixelToImageWriter.cpp +++ b/Resources/InsaneWidget/PixelToImageWriter.cpp @@ -8,14 +8,17 @@ // */ #include "PixelToImageWriter.h" -#include +#include #include +#include +#include using namespace std; bool PixelToImageWriter::Convert(const std::string& pixelFilePath, - int imageWidth, int imageHeight, - int outputFormat, wxImage * image) + int imageWidth, int imageHeight, + std::vector * descriptors, + int outputFormat, wxImage * image) { UpdateExtensionsMap(); wxImage * outImage = image; @@ -35,6 +38,16 @@ bool PixelToImageWriter::Convert(const std::string& pixelFilePath, raw.assign(istreambuf_iterator(ifs), istreambuf_iterator()); outImage->SetData((unsigned char*) raw.data(), imageWidth, imageHeight, true); // true +++ + if (descriptors) + { + for (StampDescriptor * descriptor : *descriptors) + { + if (descriptor) + { + StampWorker::StampBackground(*outImage, descriptor->image, descriptor->location); + } + } + } switch (outputFormat) { diff --git a/Resources/InsaneWidget/PixelToImageWriter.h b/Resources/InsaneWidget/PixelToImageWriter.h index 406f9b5..199ce68 100644 --- a/Resources/InsaneWidget/PixelToImageWriter.h +++ b/Resources/InsaneWidget/PixelToImageWriter.h @@ -10,19 +10,26 @@ #ifndef PIXELTOIMAGEWRITER_H #define PIXELTOIMAGEWRITER_H -#include "Common.h" +#include "DefsInsaneWidget.h" #include +#include #include +struct StampDescriptor; + /** * Create an image file from a raw scanned file.\n + * Optionally,\n + * - use an wxImage object from the application\n + * - blend a stamp image on the converted image.\n */ class PixelToImageWriter { + DECLARE_DYNAMIC_CLASS( PixelToImageWriter ) public: static bool Convert(const std::string& pixelFilePath, - int imageWidth, int imageHeight, int outputFormat = PNG, - wxImage * image = nullptr); + int imageWidth, int imageHeight, std::vector * descriptors, + int outputFormat = PNG, wxImage * image = nullptr); }; #endif // PIXELTOIMAGEWRITER_H diff --git a/Resources/InsaneWidget/PixelToPdfWriter.cpp b/Resources/InsaneWidget/PixelToPdfWriter.cpp index f92c2b8..cdf6f76 100644 --- a/Resources/InsaneWidget/PixelToPdfWriter.cpp +++ b/Resources/InsaneWidget/PixelToPdfWriter.cpp @@ -9,7 +9,11 @@ #include "PixelToPdfWriter.h" #include +#include #include +#include +#include +#include using namespace std; using namespace PoDoFo; @@ -29,8 +33,9 @@ PixelToPdfWriter::PixelToPdfWriter() } -bool PixelToPdfWriter::AddPageAt(const std::string& pixelFile, uint width, uint height, uint index, - PoDoFo::PdfPageSize pageSize, PoDoFo::PdfColorSpace) +bool PixelToPdfWriter::AddPageAt(const std::string& pixelFile, uint width, uint height, uint index, + std::vector * descriptors, + PoDoFo::PdfPageSize pageSize, PoDoFo::PdfColorSpace) { try { @@ -46,6 +51,23 @@ bool PixelToPdfWriter::AddPageAt(const std::string& pixelFile, uint width, uint ifstream ifs(pixelFile, ios::binary); string content; content.assign(istreambuf_iterator(ifs), istreambuf_iterator()); + if (descriptors) + { + for (StampDescriptor * descriptor : *descriptors) + { + if (!descriptor) + continue; + + wxImage background; + background.SetData(reinterpret_cast (content.data()), width, height, true); + StampWorker::StampBackground(background, descriptor->image, descriptor->location); + stringstream ssStamped; + ssStamped.write((const char*) (background.GetData()), width * height * 3); + ssStamped.flush(); + content.clear(); + content = ssStamped.str(); + } + } bufferview bv(content); const uint pageNumber = m_doc.GetPages().GetCount(); diff --git a/Resources/InsaneWidget/PixelToPdfWriter.h b/Resources/InsaneWidget/PixelToPdfWriter.h index faa5413..7686143 100644 --- a/Resources/InsaneWidget/PixelToPdfWriter.h +++ b/Resources/InsaneWidget/PixelToPdfWriter.h @@ -12,13 +12,18 @@ #include #include +#include #include +#include + +struct StampDescriptor; /** * Create a PDF document, append or insert pages from raw scanned files.\n * Each image is a full page scan; it is scaled in the PDF document to the full * page dimensions.\n - * Account for page size. + * Account for page size.\n + * Optionally, a stamp image may be blended on the page. */ class PixelToPdfWriter { @@ -27,6 +32,7 @@ public: PixelToPdfWriter(); bool AddPageAt(const std::string& pixelFile, uint width, uint height, uint index, + std::vector * descriptors, PoDoFo::PdfPageSize pageSize = PoDoFo::PdfPageSize::A4, PoDoFo::PdfColorSpace = PoDoFo::PdfColorSpace::DeviceRGB /*Unused*/); void Save(const std::string& pdfFile); diff --git a/Resources/InsaneWidget/UI/InsaneWidget.cpp b/Resources/InsaneWidget/UI/InsaneWidget.cpp index 6d68ed1..25fb52f 100644 --- a/Resources/InsaneWidget/UI/InsaneWidget.cpp +++ b/Resources/InsaneWidget/UI/InsaneWidget.cpp @@ -103,6 +103,7 @@ InsaneWidget::~InsaneWidget() void InsaneWidget::Init() { ////@begin InsaneWidget member initialisation + szInsaneWidgetMain = NULL; lblNewDoc = NULL; txtNewDoc = NULL; btnScan = NULL; @@ -119,11 +120,11 @@ void InsaneWidget::CreateControls() ////@begin InsaneWidget content construction InsaneWidget* itemPanel1 = this; - wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL); - itemPanel1->SetSizer(itemBoxSizer2); + szInsaneWidgetMain = new wxBoxSizer(wxVERTICAL); + itemPanel1->SetSizer(szInsaneWidgetMain); wxBoxSizer* itemBoxSizer1 = new wxBoxSizer(wxHORIZONTAL); - itemBoxSizer2->Add(itemBoxSizer1, 0, wxGROW|wxALL, 5); + szInsaneWidgetMain->Add(itemBoxSizer1, 0, wxGROW|wxALL, 5); lblNewDoc = new wxStaticText( itemPanel1, ID_NewDoc_LBL, _("New"), wxDefaultPosition, wxDefaultSize, 0 ); if (InsaneWidget::ShowToolTips()) @@ -137,7 +138,7 @@ void InsaneWidget::CreateControls() btnScan = new wxButton( itemPanel1, ID_Scan_BTN, _("Scan"), wxDefaultPosition, wxDefaultSize, 0 ); if (InsaneWidget::ShowToolTips()) - btnScan->SetToolTip(_("'Left click' to start the scan project.\n'Right click' to show the scanner widget.")); + btnScan->SetToolTip(_("'Left click' to start the scan project.\n'Right click' to show the scanner widget.\n'Ctrl + Right click' to show the Stamp dialog.")); itemBoxSizer1->Add(btnScan, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); ////@end InsaneWidget content construction diff --git a/Resources/InsaneWidget/UI/InsaneWidget.h b/Resources/InsaneWidget/UI/InsaneWidget.h index 46c6b02..6472787 100644 --- a/Resources/InsaneWidget/UI/InsaneWidget.h +++ b/Resources/InsaneWidget/UI/InsaneWidget.h @@ -25,6 +25,7 @@ */ ////@begin forward declarations +class wxBoxSizer; ////@end forward declarations /*! @@ -39,7 +40,7 @@ #define SYMBOL_INSANEWIDGET_STYLE wxTAB_TRAVERSAL #define SYMBOL_INSANEWIDGET_TITLE _("InsaneWidget") #define SYMBOL_INSANEWIDGET_IDNAME ID_INSANEWIDGET -#define SYMBOL_INSANEWIDGET_SIZE wxSize(400, 300) +#define SYMBOL_INSANEWIDGET_SIZE wxDefaultSize #define SYMBOL_INSANEWIDGET_POSITION wxDefaultPosition ////@end control identifiers @@ -87,6 +88,7 @@ public: static bool ShowToolTips(); ////@begin InsaneWidget member variables + wxBoxSizer* szInsaneWidgetMain; wxStaticText* lblNewDoc; wxTextCtrl* txtNewDoc; wxButton* btnScan; diff --git a/Resources/InsaneWidget/UI/InsaneWidget.pjd b/Resources/InsaneWidget/UI/InsaneWidget.pjd index 5fb9654..78e0b0c 100644 --- a/Resources/InsaneWidget/UI/InsaneWidget.pjd +++ b/Resources/InsaneWidget/UI/InsaneWidget.pjd @@ -245,7 +245,7 @@ "" "" "InsaneWidget.h" - 300 + -1 "" 0 "" @@ -257,7 +257,7 @@ "Tiled" "InsaneWidget" "" - 400 + -1 "wxPanel" 0 0 @@ -303,13 +303,21 @@ 0 0 1 - "" + "Centre" + "Centre" + 5 + "szInsaneWidgetMain" "Vertical" "<Any platform>" + 0 0 + 1 0 + 1 0 + 1 0 + 1 "wxBoxSizer V" 0 "dialog-control-document" @@ -538,7 +546,8 @@ 0 0 "'Left click' to start the scan project. -'Right click' to show the scanner widget." +'Right click' to show the scanner widget. +'Ctrl + Right click' to show the Stamp dialog." -1 0 1 @@ -654,13 +663,21 @@ 0 0 1 + "Centre" + "Centre" + 5 "" "Vertical" "<Any platform>" + 0 0 + 1 0 + 1 0 + 1 0 + 1 "wxBoxSizer V" 0 "dialog-control-document" diff --git a/Resources/InsaneWidget/XInsaneWidget.cpp b/Resources/InsaneWidget/XInsaneWidget.cpp index 08af79b..0c707b5 100644 --- a/Resources/InsaneWidget/XInsaneWidget.cpp +++ b/Resources/InsaneWidget/XInsaneWidget.cpp @@ -12,7 +12,10 @@ #include #include "PixelToImageWriter.h" #include "PixelToPdfWriter.h" -#include +#include +#include +#include +#include using namespace std; @@ -46,13 +49,16 @@ public: { } /* - * mode, outputType, adf, doubleSided, total, PaperSize: + * mode, resolution, outputType, adf, doubleSided, total, PaperSize: * These are not updated here if there are pending jobs. * However, * deviceId, source, sourceIndex, mode, resolution, paperSize * can be changed if there are pending jobs in ConfigureDevice() since it is * called before these setters. They won't change on their own but by user * interaction. + * The 'resolution' variable is used downstream to distinguish between v4l + * and real scanners. v4l devices do not have a source and a resolution + * tunables. */ void SetMode(const string& mode) { @@ -60,6 +66,12 @@ public: return; m_mode = mode; } + void SetResolution(int resolution) + { + if (m_pixelFiles.size()) + return; + m_resolution = resolution; + } void SetOutputType(int outputType) { if (m_pixelFiles.size()) @@ -101,6 +113,10 @@ public: return; m_paperSize = paperSize; } + void SetStampDescriptors(vector * descriptors) + { + m_stampDescriptors = descriptors; + } std::pair GetStartAndIncrement(InsaneWorker * insaneWorker) { wxASSERT_MSG(insaneWorker != nullptr, "insaneWorker is NULL."); @@ -162,11 +178,12 @@ public: m_sb->SetStatusText(msg); }; - + if (m_outputType != PDF) { // Convert pixel file to PNG using netpbm. - if (!PixelToImageWriter::Convert(filePath, imageAttributes.width, imageAttributes.height, m_outputType)) + if (!PixelToImageWriter::Convert(filePath, imageAttributes.width, imageAttributes.height, + m_stampDescriptors, m_outputType)) { const wxString msg = _("Failed to create output image."); cerr << msg << endl; @@ -191,7 +208,8 @@ public: cerr << msg << endl; pageSize = PoDoFo::PdfPageSize::A4; } - if (!m_pixelToPdfWriter->AddPageAt(filePath, imageAttributes.width, imageAttributes.height, index, pageSize)) + if (!m_pixelToPdfWriter->AddPageAt(filePath, imageAttributes.width, imageAttributes.height, index, + m_stampDescriptors, pageSize)) { const wxString msg = _("Failed to add page to PDF document."); cerr << msg << endl; @@ -241,6 +259,17 @@ public: } } } + void OnStartScanSession(uint pageIndex, const ImageAttributes& imageAttributes) override + { + if (!m_stampDescriptors) + return; + for (StampDescriptor * descriptor : *m_stampDescriptors) + { + if (descriptor->text.IsEmpty()) + continue; + descriptor->image = StampWorker::CreateStamp(descriptor, m_resolution); + } + } void Reset() { // Don't reset calculated variables that depend on widgets. @@ -255,7 +284,9 @@ private: wxWeakRef m_sb = nullptr; std::unique_ptr m_pixelToPdfWriter; PixelFilesMap m_pixelFiles; + vector * m_stampDescriptors = nullptr; string m_mode = "Color"; + int m_resolution = -1; uint m_outputType = PDF; wxString m_paperSize = _T("A4"); bool m_adf = false; @@ -268,12 +299,20 @@ private: }; // ---------------------------------------------------------------------------- +IMPLEMENT_CLASS( XInsaneWidget, InsaneWidget ) + XInsaneWidget::XInsaneWidget(wxWindow* parent, TimeredStatusBar * sb, wxConfig * config, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : InsaneWidget(parent, id, pos, size, style) { UpdateExtensionsMap(); m_config = config; m_sb = sb; +} + +XInsaneWidget::~XInsaneWidget() = default; // Important for mixing unique_ptr and PIMPL. + +void XInsaneWidget::Setup() +{ lblNewDoc->Bind ( wxEVT_RIGHT_UP, &XInsaneWidget::OnLblNewDocRightClick, this ); txtNewDoc->Bind ( wxEVT_KEY_UP, &XInsaneWidget::OnTxtNewDocKeyPressed, this ); @@ -283,7 +322,7 @@ XInsaneWidget::XInsaneWidget(wxWindow* parent, TimeredStatusBar * sb, wxConfig * m_insaneWorker = std::make_unique(m_scanProject.get()); m_scannerWidget = std::make_unique ( m_ptwScannerWidget.get(), m_sb, m_insaneWorker.get() ); m_scannerWidget->SetConfig ( m_config ); - + btnScan->Enable(false); btnScan->Bind ( wxEVT_RIGHT_UP, &XInsaneWidget::OnBtnScanRightClick, this ); btnScan->Bind ( wxEVT_LEFT_UP, &XInsaneWidget::OnBtnScanClick, this ); @@ -293,7 +332,6 @@ XInsaneWidget::XInsaneWidget(wxWindow* parent, TimeredStatusBar * sb, wxConfig * backgroundDiscovery->Run(); } -XInsaneWidget::~XInsaneWidget() = default; // Important for mixing unique_ptr and PIMPL. // Show a popup to specifiy the number of pages to scan and back-sided scanning. void XInsaneWidget::OnLblNewDocRightClick ( wxMouseEvent& evt ) @@ -328,16 +366,38 @@ void XInsaneWidget::OnTxtNewDocKeyPressed ( wxKeyEvent& evt ) evt.Skip(); } -// Show the scanner widget. +// Show the scanner widget or the stamp widgets. void XInsaneWidget::OnBtnScanRightClick ( wxMouseEvent& evt ) { - if ( m_scannerWidget->cmbDevices->GetCount() ) + if (evt.ControlDown()) { - const wxSize current = m_scannerWidget->GetSize(); - m_scannerWidget->SetSize ( wxSize ( 500, current.GetHeight() ) ); + if (!m_dlgStampWidgets) + { + m_dlgStampWidgets = std::make_unique + (nullptr, wxID_ANY, _("Stamps"), + wxDefaultPosition, wxDefaultSize, + wxCAPTION | wxRESIZE_BORDER | wxCLOSE_BOX); + m_dlgStampWidgets->SetSize(600, 500); + m_dlgStampWidgets->SetSizer(new wxBoxSizer(wxVERTICAL)); + m_dlgStampWidgets->Show ( false ); + m_stampWidgets = std::make_unique ( m_dlgStampWidgets.get()); + m_stampWidgets->Setup(m_config); + m_dlgStampWidgets->GetSizer()->Add(m_stampWidgets.get(), 1, wxGROW | wxALL, 5); + } + m_dlgStampWidgets->Show(); } - MiscTools::ShowTransientPopup ( m_ptwScannerWidget.get(), m_scannerWidget.get() ); - evt.Skip(); + else + { + if ( m_scannerWidget->cmbDevices->GetCount() ) + { + const wxSize current = m_scannerWidget->GetSize(); + m_scannerWidget->SetSize ( wxSize ( 500, current.GetHeight() ) ); + } + MiscTools::ShowTransientPopup ( m_ptwScannerWidget.get(), m_scannerWidget.get() ); + } + // +++ Prevent OnLblNewDocRightClick() from being called. + // Why is OnBtnScanRightClick() not called the other way round? + evt.Skip(false); } // Start scanning. @@ -367,7 +427,7 @@ void XInsaneWidget::OnBtnScanClick ( wxMouseEvent& evt ) const std::pair sourceAttributes = m_scannerWidget->GetScannerSource(); const string source = sourceAttributes.second.ToStdString(); const string mode = m_scannerWidget->GetScannerMode().ToStdString(); - int resolution = 300; + int resolution = -1; // No resolution with v4l devices. if ( !m_scannerWidget->GetScannerResolution().IsEmpty() ) { resolution = std::stoi ( m_scannerWidget->GetScannerResolution().ToStdString() ); @@ -379,10 +439,13 @@ void XInsaneWidget::OnBtnScanClick ( wxMouseEvent& evt ) { m_scanProject->SetADF(adf); m_scanProject->SetMode(mode); + m_scanProject->SetResolution(resolution); m_scanProject->SetOutputType(outputType); m_scanProject->SetPaperSize(paperSize); m_scanProject->SetDoubleSided(doubleSided); m_scanProject->SetTotalNumberOfSides(total); + m_stampDescriptors = m_stampWidgets->GetStampDescriptors(); + m_scanProject->SetStampDescriptors(m_stampDescriptors); std::pair startAndIncrement = m_scanProject->GetStartAndIncrement(m_insaneWorker.get()); diff --git a/Resources/InsaneWidget/XInsaneWidget.h b/Resources/InsaneWidget/XInsaneWidget.h index 4c81dac..3d02fb2 100644 --- a/Resources/InsaneWidget/XInsaneWidget.h +++ b/Resources/InsaneWidget/XInsaneWidget.h @@ -16,18 +16,23 @@ #include #include #include +#include +#include #include #include #include +#include class BackgroundScannerDiscoveryEVH; class ScanProjectHandler; // An event handler extending InsaneWorkerEvent. +class XStampWidget; +struct StampDescriptor; // Page index (not page number), {pixel file path, {pixel count, image width, image height}}. typedef std::map> PixelFilesMap; /** - * Shows a label, a disabled text box and a button. + * Shows a label, a disabled text box, and a button. * * Label: * - Right click: define the number of pages to scan and double-sided scanning. @@ -48,9 +53,11 @@ typedef std::map m_sb; + std::vector * m_stampDescriptors; // Contains a popup to define the number of pages and double-sided scanning. std::unique_ptr m_pageStack; // Contains the scanner widget. std::unique_ptr m_ptwScannerWidget; + // Contains the stamp widgets. + std::unique_ptr m_dlgStampWidgets; + std::unique_ptr m_stampWidgets; // Available devices and minimal options. std::unique_ptr m_scannerWidget; std::unique_ptr m_insaneWorker; diff --git a/Resources/InsaneWidget/XScannerWidget.cpp b/Resources/InsaneWidget/XScannerWidget.cpp index aba5634..ff6011c 100644 --- a/Resources/InsaneWidget/XScannerWidget.cpp +++ b/Resources/InsaneWidget/XScannerWidget.cpp @@ -9,13 +9,15 @@ #include "XScannerWidget.h" #include "XClientData.hpp" -#include "Common.h" +#include "DefsInsaneWidget.h" #include #include #include using namespace std; +IMPLEMENT_CLASS( XScannerWidget, ScannerWidget ) + XScannerWidget::~XScannerWidget() {} diff --git a/Resources/InsaneWidget/XScannerWidget.h b/Resources/InsaneWidget/XScannerWidget.h index a9023ec..b6b3c2a 100644 --- a/Resources/InsaneWidget/XScannerWidget.h +++ b/Resources/InsaneWidget/XScannerWidget.h @@ -16,7 +16,6 @@ #include #include "TimeredStatusBar.h" #include "InsaneWorker.h" -#include "Common.h" #include class BackgroundScannerDiscoveryEvent; @@ -33,6 +32,7 @@ class BackgroundScannerDiscoveryEvent; class XScannerWidget : public ScannerWidget { + DECLARE_DYNAMIC_CLASS( XScannerWidget ) friend class BackgroundScannerDiscovery; public: XScannerWidget() {}; diff --git a/Resources/Lokalize/fr/S7.po b/Resources/Lokalize/fr/S7.po index dedab92..a1366b3 100644 --- a/Resources/Lokalize/fr/S7.po +++ b/Resources/Lokalize/fr/S7.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-06-26 22:47+0200\n" -"PO-Revision-Date: 2025-06-26 22:47+0200\n" +"POT-Creation-Date: 2025-07-09 16:00+0200\n" +"PO-Revision-Date: 2025-07-09 16:03+0200\n" "Last-Translator: Saleem EDAH-TALLY \n" "Language-Team: French \n" "Language: fr_FR\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Lokalize 25.04.2\n" +"X-Generator: Lokalize 25.04.3\n" #: ../../Resources/UI/S7/s7.cpp:126 ../..//Resources/UI/S7/s7.cpp:126 msgid "" @@ -40,14 +40,23 @@ msgstr "" "'CTRL + clic' : à propos" #: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:128 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:129 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:132 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:125 msgid "New" msgstr "Nouveau" #: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:130 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:131 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:134 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:127 msgid "'Right' click to define a scan project." msgstr "Clic droit pour définir un projet de numérisation" #: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:135 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:136 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:139 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:132 msgid "" "Full path to destination file without the extension; it is determined by the " "output type." @@ -56,10 +65,15 @@ msgstr "" "déterminée par le format de sortie." #: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:138 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:139 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:142 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:135 msgid "Scan" msgstr "Numériser" #: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:140 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:141 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:144 msgid "" "'Left click' to start the scan project.\n" "'Right click' to show the scanner widget." @@ -93,41 +107,57 @@ msgstr "Résolution de la numérisation" #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:128 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:107 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:132 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:133 msgid "A scan library error occurred." msgstr "Une erreur de bibliothèque est survenue." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:134 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:113 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:138 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:139 msgid "A general error occurred." msgstr "Une erreur générale est survenue." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:138 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:117 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:142 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:143 msgid "A session read error occurred." msgstr "Une erreur de lecture est survenue." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:145 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:124 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:149 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:150 msgid "Session cancelled." msgstr "Session annulée." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:162 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:141 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:166 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:167 msgid "Scanning: " msgstr "Numérisation :" #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:164 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:143 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:168 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:169 msgid "Front face: " msgstr "Recto :" #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:166 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:145 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:170 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:171 msgid "Back face: " msgstr "Verso :" #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:170 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:149 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:174 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:175 msgid ". Turn the whole stack of pages." msgstr ". Retournez toute la pile de pages." @@ -138,16 +168,23 @@ msgstr "Échec de création d'image PNG." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:201 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:180 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:206 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:207 msgid "Wrong paper size: " msgstr "Mauvaise taille de papier :" #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:201 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:180 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:206 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:207 msgid "; using A4." msgstr "; utilisation du format A4." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:207 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:186 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:212 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:213 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:214 msgid "Failed to add page to PDF document." msgstr "Échec d'ajout de page au document PDF." @@ -160,17 +197,28 @@ msgstr "Format de fichier de sortie non pris en charge." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:264 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:243 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:255 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:256 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:257 msgid "Finished." msgstr "Terminé." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:333 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:317 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:356 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:355 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:351 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:352 msgid "Scan all front faces first, then all back faces in reverse order." msgstr "" "Numériser tous les faces recto, puis toutes les faces verso en ordre inverse." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:336 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:320 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:359 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:358 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:354 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:355 msgid "Total number of sides to scan (not total number of sheets)." msgstr "" "Nombre total de faces à numériser (et non pas le nombre total de feuilles)." @@ -188,10 +236,14 @@ msgid "CAPS" msgstr "CAPS" #: ../../Resources/InsaneWidget/XScannerWidget.cpp:50 +#: ../../Resources/InsaneWidget/XScannerWidget.cpp:62 +#: ../../Resources/InsaneWidget/XScannerWidget.cpp:64 msgid "Searching for devices..." msgstr "Recherche de périphériques..." #: ../../Resources/InsaneWidget/XScannerWidget.cpp:53 +#: ../../Resources/InsaneWidget/XScannerWidget.cpp:65 +#: ../../Resources/InsaneWidget/XScannerWidget.cpp:67 msgid "Could not initialise insane api." msgstr "Échec d'initialisation de la bibliothèque 'insane'." @@ -199,23 +251,23 @@ msgstr "Échec d'initialisation de la bibliothèque 'insane'." msgid "'Shift + left' click'' to generate a new destination file name." msgstr "'Maj + clic gauche' pour générer un nouveau fichier de sortie." -#: ../../XS7.cpp:69 ../../XS7.cpp:104 +#: ../../XS7.cpp:69 ../../XS7.cpp:104 ../../XS7.cpp:105 ../../XS7.cpp:107 msgid "Could not launch default file manager" msgstr "Échec de lancement du gestionnaire de fichier par défaut." -#: ../../XS7.cpp:93 ../../XS7.cpp:128 +#: ../../XS7.cpp:93 ../../XS7.cpp:128 ../../XS7.cpp:129 ../../XS7.cpp:131 msgid "Invalid folder name." msgstr "Nom de dossier invalide." -#: ../../XS7.cpp:101 ../../XS7.cpp:136 +#: ../../XS7.cpp:101 ../../XS7.cpp:136 ../../XS7.cpp:137 ../../XS7.cpp:139 msgid "Invalid file basename." msgstr "Nom de base de fichier invalide." -#: ../../XS7.cpp:123 ../../XS7.cpp:158 +#: ../../XS7.cpp:123 ../../XS7.cpp:158 ../../XS7.cpp:159 ../../XS7.cpp:161 msgid "Copyright: Saleem Edah-Tally [Surgeon] [Hobbyist developer]\n" msgstr "Copyright: Saleem Edah-Tally [Chirurgien] [Développeur par hobby]\n" -#: ../../XS7.cpp:124 ../../XS7.cpp:159 +#: ../../XS7.cpp:124 ../../XS7.cpp:159 ../../XS7.cpp:160 ../../XS7.cpp:162 msgid "License: CeCILL/CeCILL-C per file header." msgstr "Licence : CeCILL/CeCILL-C selon les entêtes de fichier." @@ -224,6 +276,9 @@ msgid "S7" msgstr "S7" #: ../../Resources/InsaneWidget/UI/InsaneWidget.h:40 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.h:45 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.h:49 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.h:41 msgid "InsaneWidget" msgstr "InsaneWidget" @@ -257,23 +312,32 @@ msgstr "Format de page :" #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:332 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:316 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:355 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:354 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:350 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:351 msgid "Double sided:" msgstr "Recto-verso :" #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:334 #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:318 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:357 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:356 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:352 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:353 msgid "Total:" msgstr "Total :" -#: ../../XS7.cpp:46 ../../XS7.cpp:81 +#: ../../XS7.cpp:46 ../../XS7.cpp:81 ../../XS7.cpp:82 ../../XS7.cpp:84 msgid "'Shift + left' click to generate a new destination file name." msgstr "'Maj + clic gauche' pour générer un nouveau fichier de sortie." -#: ../../XS7.cpp:121 ../../XS7.cpp:45 ../../XS7.cpp:156 +#: ../../XS7.cpp:121 ../../XS7.cpp:45 ../../XS7.cpp:156 ../../XS7.cpp:157 +#: ../../XS7.cpp:47 ../../XS7.cpp:159 msgid " - version " msgstr " - version " -#: ../../XS7.cpp:122 ../../XS7.cpp:157 +#: ../../XS7.cpp:122 ../../XS7.cpp:157 ../../XS7.cpp:158 ../../XS7.cpp:160 msgid "" ", using InsaneWidget.\n" "\n" @@ -282,21 +346,222 @@ msgstr "" "\n" #: ../../Resources/InsaneWidget/XScannerWidget.cpp:73 +#: ../../Resources/InsaneWidget/XScannerWidget.cpp:85 +#: ../../Resources/InsaneWidget/XScannerWidget.cpp:87 msgid " device(s) found." msgstr " périphériques trouvé(s)." -#: ../../XS7.cpp:29 +#: ../../XS7.cpp:29 ../../XS7.cpp:31 msgid "Config file tag." msgstr "Suffixe du fichier de configuration." -#: ../../XS7.cpp:30 +#: ../../XS7.cpp:30 ../../XS7.cpp:32 msgid "Show version and quit." msgstr "Afficher la version et quitter." -#: ../../XS7.cpp:31 +#: ../../XS7.cpp:31 ../../XS7.cpp:33 msgid "Show help and quit." msgstr "Afficher l'aide et quitter." #: ../../Resources/InsaneWidget/XInsaneWidget.cpp:352 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:391 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:390 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:408 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:409 msgid "Destination file missing." msgstr "Fichier de destination manquant." + +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:130 +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:131 +#: ../../Resources/StampWidget/UI/StampWidget.cpp:140 +msgid "" +"Create a stamp with this text, which can be multiline.\n" +"\n" +"CTRL + S: save the current text.\n" +"CTRL + R: restore the saved text." +msgstr "" +"Créer un tampon utilisant ce texte qui peut être multi-ligne.\n" +"\n" +"CTRL + S : sauvegarder le texte actuel.\n" +"CTRL + R : restaurer le texte sauvegardé." + +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:138 +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:139 +#: ../../Resources/StampWidget/UI/StampWidget.cpp:188 +msgid "Select the font of the stamp text." +msgstr "Sélectionnez la police de caractère du texte." + +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:143 +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:144 +msgid "Select the colour of the stamp text." +msgstr "Sélectionnez la couleur du texte." + +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:148 +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:155 +#: ../../Resources/StampWidget/UI/StampWidget.cpp:199 +msgid "Select the rotation angle of the stamp text." +msgstr "Sélectionnez l'angle de rotation du texte." + +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:144 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:147 +msgid "Stamp" +msgstr "Tampon" + +#: ../../Resources/InsaneWidget/PixelToImageWriter.cpp:34 +#: ../../Resources/InsaneWidget/PixelToImageWriter.cpp:35 +msgid "Failed to read raw file." +msgstr "Échec de lecture du fichier brut." + +#: ../../Resources/InsaneWidget/PixelToImageWriter.cpp:60 +#: ../../Resources/InsaneWidget/PixelToImageWriter.cpp:68 +#: ../../Resources/InsaneWidget/PixelToImageWriter.cpp:69 +msgid "Unhandled output image format." +msgstr "Format de fichier d'image en sortie non pris en charge." + +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:187 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:188 +msgid "Failed to create output image." +msgstr "Échec de création de l'image de sortie." + +#: ../../Resources/InsaneWidget/UI/StampWidget.h:46 +#: ../../Resources/InsaneWidget/UI/StampWidget.h:47 +#: ../../Resources/StampWidget/UI/StampWidget.h:57 +msgid "StampWidget" +msgstr "" + +#: ../../Resources/InsaneWidget/UI/StampWidget.cpp:150 +#: ../../Resources/StampWidget/UI/StampWidget.cpp:171 +msgid "Location of the stamp on the output." +msgstr "Place du tampon dans la sortie." + +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:156 +#: ../../Resources/InsaneWidget/UI/StampWidgets.cpp:127 +#: ../../Resources/StampWidget/UI/StampWidgets.cpp:127 +msgid "+" +msgstr "" + +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:158 +#: ../../Resources/InsaneWidget/UI/StampWidgets.cpp:129 +#: ../../Resources/StampWidget/UI/StampWidgets.cpp:129 +msgid "Add a stamp widget." +msgstr "Ajouter un widget 'Tampon'." + +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:161 +#: ../../Resources/InsaneWidget/UI/StampWidgets.cpp:132 +#: ../../Resources/StampWidget/UI/StampWidgets.cpp:132 +msgid "-" +msgstr "" + +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:163 +#: ../../Resources/InsaneWidget/UI/StampWidgets.cpp:134 +#: ../../Resources/StampWidget/UI/StampWidgets.cpp:134 +msgid "Remove the selected stamp widget." +msgstr "Supprimer le widget 'Tampon' sélectionné." + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:56 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:57 +#: ../../Resources/StampWidget/XStampWidget.cpp:76 +msgid "Centre" +msgstr "Centre" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:57 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:58 +#: ../../Resources/StampWidget/XStampWidget.cpp:77 +msgid "North" +msgstr "Nord" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:57 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:58 +#: ../../Resources/StampWidget/XStampWidget.cpp:77 +msgid "South" +msgstr "Sud" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:57 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:58 +#: ../../Resources/StampWidget/XStampWidget.cpp:77 +msgid "West" +msgstr "Ouest" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:58 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:59 +#: ../../Resources/StampWidget/XStampWidget.cpp:78 +msgid "North-east" +msgstr "Nord-est" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:58 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:59 +#: ../../Resources/StampWidget/XStampWidget.cpp:78 +msgid "North-west" +msgstr "Nord-ouest" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:59 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:60 +#: ../../Resources/StampWidget/XStampWidget.cpp:79 +msgid "South-east" +msgstr "Sud-est" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:59 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:60 +#: ../../Resources/StampWidget/XStampWidget.cpp:79 +msgid "South-west" +msgstr "Sud-ouest" + +#: ../../Resources/InsaneWidget/XStampWidget.cpp:57 +#: ../../Resources/InsaneWidget/XStampWidget.cpp:58 +#: ../../Resources/StampWidget/XStampWidget.cpp:77 +msgid "East" +msgstr "Est" + +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:137 +#: ../../Resources/InsaneWidget/UI/InsaneWidget.cpp:141 +msgid "" +"'Left click' to start the scan project.\n" +"'Right click' to show the scanner widget.\n" +"'Ctrl + Right click' to show the Stamp dialog." +msgstr "" +"'Clic gauche' pour démarrer la numérisation.\n" +"'Clic droit' pour afficher les options du numériseur.\n" +"'Ctrl + Clic droit' pour définir un tampon." + +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:376 +#: ../../Resources/InsaneWidget/XInsaneWidget.cpp:377 +msgid "Stamps" +msgstr "Tampons" + +#: ../../Resources/InsaneWidget/UI/StampWidgets.h:44 +#: ../../Resources/StampWidget/UI/StampWidgets.h:44 +msgid "StampWidgets" +msgstr "" + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:149 +msgid "Foreground:" +msgstr "Avant-plan :" + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:154 +msgid "Foreground colour of the text." +msgstr "Couleur du texte." + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:157 +msgid "Background:" +msgstr "Arrière-plan :" + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:162 +msgid "Background colour of the text." +msgstr "Couleur de l'arrière-plan." + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:165 +msgid "Location:" +msgstr "Position :" + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:177 +msgid "Click to update the preview." +msgstr "Cliquez pour actualiser l'aperçu." + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:191 +msgid "Transparent" +msgstr "Transparent" + +#: ../../Resources/StampWidget/UI/StampWidget.cpp:194 +msgid "" +"Check for a completely transparent background and for a transparent text." +msgstr "Activez la transparence du texte et de l'arrière-plan. " diff --git a/Resources/PKGBUILD b/Resources/PKGBUILD index 01a00e7..f055f53 100644 --- a/Resources/PKGBUILD +++ b/Resources/PKGBUILD @@ -1,7 +1,7 @@ #Simple PKGBUILD that suits my need. pkgname=(s7) -pkgver=1 +pkgver=2 pkgrel=0 arch=('x86_64' 'i686' 'armv7h' 'aarch64') url='http://github.com/nmset/s7/' diff --git a/Resources/StampWidget/CMakeLists.txt b/Resources/StampWidget/CMakeLists.txt new file mode 100644 index 0000000..7cd8547 --- /dev/null +++ b/Resources/StampWidget/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.5) + +project(StampWidget) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") + +find_package(wxWidgets COMPONENTS base core CONFIG REQUIRED) + +include_directories(${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/UI) + +add_library(stampwidget STATIC + + DefsStampWidget.h + UI/StampWidget.cpp + UI/StampWidgets.cpp + XStampWidget.cpp + XStampWidgets.cpp + StampWorker.cpp) + +target_link_libraries(stampwidget + ${wxWidgets_LIBRARIES}) diff --git a/Resources/StampWidget/DefsStampWidget.h b/Resources/StampWidget/DefsStampWidget.h new file mode 100644 index 0000000..7f0eb1f --- /dev/null +++ b/Resources/StampWidget/DefsStampWidget.h @@ -0,0 +1,30 @@ +// /* +// * File: Common.h +// * Author: Saleem Edah-Tally - nmset@yandex.com +// * License : CeCILL-C +// * Copyright Saleem Edah-Tally - © 2025 +// * +// * Created on 27 06 2025, 20:34 +// */ + +#ifndef COMMON_H +#define COMMON_H + +#include + +// ---------------------------------------------------------------------------- +enum {CENTRE = 0, NORTH, SOUTH, EAST, WEST, + NORTH_EAST, NORTH_WEST, SOUTH_EAST, SOUTH_WEST}; + +struct StampDescriptor +{ + wxImage image; + wxString text; + wxFont font = wxNullFont; + wxColour foregroundColour = wxNullColour; + wxColour backgroundColour = wxNullColour; + int rotationAngle = 45; + int location = 0; + bool transparent = true; +}; +#endif // COMMON_H diff --git a/Resources/StampWidget/StampWorker.cpp b/Resources/StampWidget/StampWorker.cpp new file mode 100644 index 0000000..e8d59ff --- /dev/null +++ b/Resources/StampWidget/StampWorker.cpp @@ -0,0 +1,121 @@ +// /* +// * File: StampWorker.cpp +// * Author: Saleem Edah-Tally - nmset@yandex.com +// * License : CeCILL-C +// * Copyright Saleem Edah-Tally - © 2025 +// * +// * Created on 02 07 2025, 21:23 +// */ + +#include "StampWorker.h" +#include // M_PI + +wxImage StampWorker::CreateStamp(StampDescriptor * descriptor, int scanResolution) +{ + /* + * Rescale the font point size of the stamp according to the scan resolution. + * Exclude rescaling on v4l that does not have a resolution parameter. + */ + wxFont dcFont(descriptor->font); + double scale = (scanResolution > 0) + ? (double) scanResolution / 72.0 + :1.0; + + wxCoord extentWidth, extentHeight, textLineHeight; + { + wxMemoryDC dc; + if (scale != 1.0) + dcFont.SetFractionalPointSize(descriptor->font.GetFractionalPointSize() * scale); + dc.SetFont(dcFont); // Mandatory despite set below. + dc.GetMultiLineTextExtent(descriptor->text, &extentWidth, &extentHeight, &textLineHeight, &dcFont); + } + wxBitmap bmp; + // bmp.UseAlpha(true); // Not mandatory. + bmp.Create(extentWidth, extentHeight); // Memo: See CreateWithDIPSize + wxImage img0, img; + + wxMemoryDC dc(bmp); + dc.SetFont(dcFont); + if (descriptor->transparent) + { + // +++, Use the red channel only: used by ConvertColourToAlpha(). + // The chosen value is inversely proportional to the transparency of the text itself. + dc.SetTextForeground(wxColour(128, 0, 0)); // A good mean is reasonable. + dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT); + } + else + { + dc.SetTextForeground(descriptor->foregroundColour); + dc.SetTextBackground(descriptor->backgroundColour); + dc.SetBackgroundMode(wxBRUSHSTYLE_SOLID); + } + + dc.DrawText(descriptor->text, wxPoint(0, 0)); + + img0 = bmp.ConvertToImage(); + if (!descriptor->transparent) + img0.InitAlpha(); // So that there is no dark surrounding if it is rotated. + + img = img0.Rotate((M_PI / 180.0) * descriptor->rotationAngle, wxPoint(0, 0)); + if (descriptor->transparent) + { + img.ConvertColourToAlpha(descriptor->foregroundColour.GetRed(), + descriptor->foregroundColour.GetGreen(), + descriptor->foregroundColour.GetBlue()); // The target colour is passed in. + img.ChangeSaturation(-0.7); // Slightly better looking. + } + + return img; +} + +void StampWorker::StampBackground(wxImage& background, + const wxImage& stamp, int location) +{ + // Simply pasting the stamp on the background, i.e., the scanned page. + wxPoint bgCentre(background.GetWidth() / 2, background.GetHeight() / 2); + wxPoint stampCentre(stamp.GetWidth() / 2, stamp.GetHeight() / 2); + int x = 0, y = 0; + switch (location) + { + case NORTH: + x = bgCentre.x - stampCentre.x; + y = 0; + break; + case SOUTH: + x = bgCentre.x - stampCentre.x; + y = background.GetHeight() - stamp.GetHeight(); + break; + case EAST: + x = background.GetWidth() - stamp.GetWidth(); + y = bgCentre.y - stampCentre.y; + break; + case WEST: + x = 0; + y = bgCentre.y - stampCentre.y; + break; + case NORTH_EAST: + x = background.GetWidth() - stamp.GetWidth(); + y = 0; + break; + case NORTH_WEST: + x = 0; + y = 0; + break; + case SOUTH_EAST: + x = background.GetWidth() - stamp.GetWidth(); + y = background.GetHeight() - stamp.GetHeight(); + break; + case SOUTH_WEST: + x = 0; + y = background.GetHeight() - stamp.GetHeight(); + break; + default: // CENTRE + x = bgCentre.x - stampCentre.x; + y = bgCentre.y - stampCentre.y; + break; + } + + wxPoint stampLocation(x, y); + background.Paste(stamp, stampLocation.x, stampLocation.y, wxIMAGE_ALPHA_BLEND_COMPOSE); +} + diff --git a/Resources/StampWidget/StampWorker.h b/Resources/StampWidget/StampWorker.h new file mode 100644 index 0000000..7361d5e --- /dev/null +++ b/Resources/StampWidget/StampWorker.h @@ -0,0 +1,38 @@ +// /* +// * File: StampWorker.h +// * Author: Saleem Edah-Tally - nmset@yandex.com +// * License : CeCILL-C +// * Copyright Saleem Edah-Tally - © 2025 +// * +// * Created on 02 07 2025, 21:23 +// */ + +#ifndef STAMPWORKER_H +#define STAMPWORKER_H + +#include +#include "DefsStampWidget.h" + +struct StampDescriptor; + +/** + * A stamp is understood here as\n + * - a transparent text in a transparent frame with no borders\n + * - an opaque text on an opaque background with no borders.\n + * + * The text may be rotated. Actually, an initial image with the text is rotated + * and its new orthogonal bounds accepted (fortunately, we don't have to compute + * that).\n + * The font point size is rescaled to match the scan resolution. If the + * scanResolution parameter is invalid (<=0), the font is not rescaled. + */ +class StampWorker +{ + DECLARE_DYNAMIC_CLASS( StampWorker ) +public: + static wxImage CreateStamp(StampDescriptor * descriptor, int scanResolution = -1); + static void StampBackground(wxImage& background, const wxImage& stamp, int location = CENTRE); + +}; + +#endif // STAMPWORKER_H diff --git a/Resources/StampWidget/UI/StampWidget.cpp b/Resources/StampWidget/UI/StampWidget.cpp new file mode 100644 index 0000000..dbfdaf0 --- /dev/null +++ b/Resources/StampWidget/UI/StampWidget.cpp @@ -0,0 +1,239 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: StampWidget.cpp +// Purpose: +// Author: Saleem EDAH-TALLY +// Modified by: +// Created: mar. 01 juil. 2025 19:14:05 +// RCS-ID: +// Copyright: Copyright Saleem EDAH-TALLY. All rights reserved. +// Licence: +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +////@begin includes +////@end includes + +#include "StampWidget.h" + +////@begin XPM images +////@end XPM images + + +/* + * StampWidget type definition + */ + +IMPLEMENT_DYNAMIC_CLASS( StampWidget, wxPanel ) + + +/* + * StampWidget event table definition + */ + +BEGIN_EVENT_TABLE( StampWidget, wxPanel ) + +////@begin StampWidget event table entries +////@end StampWidget event table entries + +END_EVENT_TABLE() + + +/* + * StampWidget constructors + */ + +StampWidget::StampWidget() +{ + Init(); +} + +StampWidget::StampWidget( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) +{ + Init(); + Create(parent, id, pos, size, style); +} + + +/* + * StampWidget creator + */ + +bool StampWidget::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) +{ +////@begin StampWidget creation + SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY); + wxPanel::Create( parent, id, pos, size, style ); + + CreateControls(); + if (GetSizer()) + { + GetSizer()->SetSizeHints(this); + } + Centre(); +////@end StampWidget creation + return true; +} + + +/* + * StampWidget destructor + */ + +StampWidget::~StampWidget() +{ +////@begin StampWidget destruction +////@end StampWidget destruction +} + + +/* + * Member initialisation + */ + +void StampWidget::Init() +{ +////@begin StampWidget member initialisation + szStampWidgetMain = NULL; + txtStamp = NULL; + szStampWidgetH0 = NULL; + szStampWidgetFlexGrid = NULL; + lblForegroundColour = NULL; + cpkForegroundStamp = NULL; + lblBackgroundColour = NULL; + cpkBackgroundStamp = NULL; + lblLocation = NULL; + cmbStampLocation = NULL; + panBitmapPreview = NULL; + szBitmapPreviewInPanel = NULL; + szStampWidgetH1 = NULL; + fpkStamp = NULL; + tglTransparent = NULL; + sldTextRotationAngle = NULL; +////@end StampWidget member initialisation +} + + +/* + * Control creation for StampWidget + */ + +void StampWidget::CreateControls() +{ +////@begin StampWidget content construction + StampWidget* itemPanel1 = this; + + szStampWidgetMain = new wxBoxSizer(wxVERTICAL); + itemPanel1->SetSizer(szStampWidgetMain); + + txtStamp = new wxTextCtrl( itemPanel1, ID_TEXTCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE ); + if (StampWidget::ShowToolTips()) + txtStamp->SetToolTip(_("Create a stamp with this text, which can be multiline.\n\nCTRL + S: save the current text.\nCTRL + R: restore the saved text.")); + szStampWidgetMain->Add(txtStamp, 0, wxGROW|wxALL, 5); + + szStampWidgetH0 = new wxBoxSizer(wxHORIZONTAL); + szStampWidgetMain->Add(szStampWidgetH0, 0, wxALIGN_LEFT|wxALL, 5); + + szStampWidgetFlexGrid = new wxFlexGridSizer(0, 2, 0, 0); + szStampWidgetH0->Add(szStampWidgetFlexGrid, 1, wxGROW|wxALL, 5); + + lblForegroundColour = new wxStaticText( itemPanel1, ID_STATIC_FOREGROUND_COLOUR, _("Foreground:"), wxDefaultPosition, wxDefaultSize, 0 ); + szStampWidgetFlexGrid->Add(lblForegroundColour, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); + + cpkForegroundStamp = new wxColourPickerCtrl( itemPanel1, ID_COLOURCTRL_FOREGROUND, wxColour(), wxDefaultPosition, wxDefaultSize, wxCLRP_DEFAULT_STYLE ); + if (StampWidget::ShowToolTips()) + cpkForegroundStamp->SetToolTip(_("Foreground colour of the text.")); + szStampWidgetFlexGrid->Add(cpkForegroundStamp, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); + + lblBackgroundColour = new wxStaticText( itemPanel1, ID_STATIC_BACKGROUND_COLOUR, _("Background:"), wxDefaultPosition, wxDefaultSize, 0 ); + szStampWidgetFlexGrid->Add(lblBackgroundColour, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); + + cpkBackgroundStamp = new wxColourPickerCtrl( itemPanel1, ID_COLOURCTRL_BACKGROUND, wxColour(255, 255, 255), wxDefaultPosition, wxDefaultSize, wxCLRP_DEFAULT_STYLE ); + if (StampWidget::ShowToolTips()) + cpkBackgroundStamp->SetToolTip(_("Background colour of the text.")); + szStampWidgetFlexGrid->Add(cpkBackgroundStamp, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); + + lblLocation = new wxStaticText( itemPanel1, ID_STATIC_LOCATION, _("Location:"), wxDefaultPosition, wxDefaultSize, 0 ); + szStampWidgetFlexGrid->Add(lblLocation, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL|wxALL, 5); + + wxArrayString cmbStampLocationStrings; + cmbStampLocation = new wxComboBox( itemPanel1, ID_COMBOBOX, wxEmptyString, wxDefaultPosition, wxDefaultSize, cmbStampLocationStrings, wxCB_READONLY ); + if (StampWidget::ShowToolTips()) + cmbStampLocation->SetToolTip(_("Location of the stamp on the output.")); + szStampWidgetFlexGrid->Add(cmbStampLocation, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 5); + + panBitmapPreview = new wxPanel( itemPanel1, ID_PANEL_BITMAP_PREVIEW, wxDefaultPosition, wxSize(200, 200), wxSUNKEN_BORDER|wxTAB_TRAVERSAL ); + panBitmapPreview->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY); + if (StampWidget::ShowToolTips()) + panBitmapPreview->SetToolTip(_("Click to update the preview.")); + szStampWidgetH0->Add(panBitmapPreview, 0, wxALIGN_TOP|wxALL, 5); + + szBitmapPreviewInPanel = new wxBoxSizer(wxVERTICAL); + panBitmapPreview->SetSizer(szBitmapPreviewInPanel); + + szStampWidgetH1 = new wxBoxSizer(wxHORIZONTAL); + szStampWidgetMain->Add(szStampWidgetH1, 0, wxGROW|wxALL, 5); + + fpkStamp = new wxFontPickerCtrl( itemPanel1, ID_FONTCTRL, wxFont(), wxDefaultPosition, wxDefaultSize, wxFNTP_FONTDESC_AS_LABEL ); + if (StampWidget::ShowToolTips()) + fpkStamp->SetToolTip(_("Select the font of the stamp text.")); + szStampWidgetH1->Add(fpkStamp, 1, wxGROW|wxALL, 5); + + tglTransparent = new wxToggleButton( itemPanel1, ID_TOGGLE_TRANSPARENT, _("Transparent"), wxDefaultPosition, wxDefaultSize, 0 ); + tglTransparent->SetValue(true); + if (StampWidget::ShowToolTips()) + tglTransparent->SetToolTip(_("Check for a completely transparent background and for a transparent text.")); + szStampWidgetH1->Add(tglTransparent, 0, wxGROW|wxALL, 5); + + sldTextRotationAngle = new wxSlider( itemPanel1, ID_SLIDER, 45, -180, 180, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_AUTOTICKS|wxSL_LABELS ); + if (StampWidget::ShowToolTips()) + sldTextRotationAngle->SetToolTip(_("Select the rotation angle of the stamp text.")); + szStampWidgetMain->Add(sldTextRotationAngle, 0, wxGROW|wxALL, 5); + +////@end StampWidget content construction +} + + +/* + * Should we show tooltips? + */ + +bool StampWidget::ShowToolTips() +{ + return true; +} + +/* + * Get bitmap resources + */ + +wxBitmap StampWidget::GetBitmapResource( const wxString& name ) +{ + // Bitmap retrieval +////@begin StampWidget bitmap retrieval + wxUnusedVar(name); + return wxNullBitmap; +////@end StampWidget bitmap retrieval +} + +/* + * Get icon resources + */ + +wxIcon StampWidget::GetIconResource( const wxString& name ) +{ + // Icon retrieval +////@begin StampWidget icon retrieval + wxUnusedVar(name); + return wxNullIcon; +////@end StampWidget icon retrieval +} diff --git a/Resources/StampWidget/UI/StampWidget.h b/Resources/StampWidget/UI/StampWidget.h new file mode 100644 index 0000000..479ddd4 --- /dev/null +++ b/Resources/StampWidget/UI/StampWidget.h @@ -0,0 +1,129 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: StampWidget.h +// Purpose: +// Author: Saleem EDAH-TALLY +// Modified by: +// Created: mar. 01 juil. 2025 19:14:05 +// RCS-ID: +// Copyright: Copyright Saleem EDAH-TALLY. All rights reserved. +// Licence: +///////////////////////////////////////////////////////////////////////////// + +#ifndef _STAMPWIDGET_H_ +#define _STAMPWIDGET_H_ + + +/*! + * Includes + */ + +////@begin includes +#include "wx/clrpicker.h" +#include "wx/fontpicker.h" +#include "wx/tglbtn.h" +////@end includes +#include "wx/combobox.h" +#include "wx/stattext.h" +/*! + * Forward declarations + */ + +////@begin forward declarations +class wxBoxSizer; +class wxFlexGridSizer; +class wxColourPickerCtrl; +class wxFontPickerCtrl; +class wxToggleButton; +////@end forward declarations + +/*! + * Control identifiers + */ + +////@begin control identifiers +#define ID_STAMPWIDGET 10000 +#define ID_TEXTCTRL 10001 +#define ID_STATIC_FOREGROUND_COLOUR 10008 +#define ID_COLOURCTRL_FOREGROUND 10003 +#define ID_STATIC_BACKGROUND_COLOUR 10009 +#define ID_COLOURCTRL_BACKGROUND 10006 +#define ID_STATIC_LOCATION 10010 +#define ID_COMBOBOX 10005 +#define ID_PANEL_BITMAP_PREVIEW 10011 +#define ID_FONTCTRL 10002 +#define ID_TOGGLE_TRANSPARENT 10007 +#define ID_SLIDER 10004 +#define SYMBOL_STAMPWIDGET_STYLE wxTAB_TRAVERSAL +#define SYMBOL_STAMPWIDGET_TITLE _("StampWidget") +#define SYMBOL_STAMPWIDGET_IDNAME ID_STAMPWIDGET +#define SYMBOL_STAMPWIDGET_SIZE wxSize(400, 300) +#define SYMBOL_STAMPWIDGET_POSITION wxDefaultPosition +////@end control identifiers + +#include +#include + +/*! + * StampWidget class declaration + */ + +class StampWidget: public wxPanel +{ + DECLARE_DYNAMIC_CLASS( StampWidget ) + DECLARE_EVENT_TABLE() + +public: + /// Constructors + StampWidget(); + StampWidget( wxWindow* parent, wxWindowID id = SYMBOL_STAMPWIDGET_IDNAME, const wxPoint& pos = SYMBOL_STAMPWIDGET_POSITION, const wxSize& size = SYMBOL_STAMPWIDGET_SIZE, long style = SYMBOL_STAMPWIDGET_STYLE ); + + /// Creation + bool Create( wxWindow* parent, wxWindowID id = SYMBOL_STAMPWIDGET_IDNAME, const wxPoint& pos = SYMBOL_STAMPWIDGET_POSITION, const wxSize& size = SYMBOL_STAMPWIDGET_SIZE, long style = SYMBOL_STAMPWIDGET_STYLE ); + + /// Destructor + ~StampWidget(); + + /// Initialises member variables + void Init(); + + /// Creates the controls and sizers + void CreateControls(); + +////@begin StampWidget event handler declarations + +////@end StampWidget event handler declarations + +////@begin StampWidget member function declarations + + /// Retrieves bitmap resources + wxBitmap GetBitmapResource( const wxString& name ); + + /// Retrieves icon resources + wxIcon GetIconResource( const wxString& name ); +////@end StampWidget member function declarations + + /// Should we show tooltips? + static bool ShowToolTips(); + +////@begin StampWidget member variables + wxBoxSizer* szStampWidgetMain; + wxTextCtrl* txtStamp; + wxBoxSizer* szStampWidgetH0; + wxFlexGridSizer* szStampWidgetFlexGrid; + wxStaticText* lblForegroundColour; + wxColourPickerCtrl* cpkForegroundStamp; + wxStaticText* lblBackgroundColour; + wxColourPickerCtrl* cpkBackgroundStamp; + wxStaticText* lblLocation; + wxComboBox* cmbStampLocation; + wxPanel* panBitmapPreview; + wxBoxSizer* szBitmapPreviewInPanel; + wxBoxSizer* szStampWidgetH1; + wxFontPickerCtrl* fpkStamp; + wxToggleButton* tglTransparent; + wxSlider* sldTextRotationAngle; +////@end StampWidget member variables +}; + +#endif + // _STAMPWIDGET_H_ diff --git a/Resources/StampWidget/UI/StampWidget.pjd b/Resources/StampWidget/UI/StampWidget.pjd new file mode 100644 index 0000000..9b78b35 --- /dev/null +++ b/Resources/StampWidget/UI/StampWidget.pjd @@ -0,0 +1,1612 @@ + + +
+ 1 + "Application" + "app.h" + "app.cpp" + "Standard" + 0 + 1 + 1 + "" + "<None>" + "Copyright Saleem EDAH-TALLY. All rights reserved." + " /// %BODY% +" + " +/* + * %BODY% + */ + +" + "///////////////////////////////////////////////////////////////////////////// +// Name: %HEADER-FILENAME% +// Purpose: +// Author: %AUTHOR% +// Modified by: +// Created: %DATE% +// RCS-ID: +// Copyright: %COPYRIGHT% +// Licence: +///////////////////////////////////////////////////////////////////////////// + +" + "" + "///////////////////////////////////////////////////////////////////////////// +// Name: %SOURCE-FILENAME% +// Purpose: +// Author: %AUTHOR% +// Modified by: +// Created: %DATE% +// RCS-ID: +// Copyright: %COPYRIGHT% +// Licence: +///////////////////////////////////////////////////////////////////////////// + +" + "// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +" + "///////////////////////////////////////////////////////////////////////////// +// Name: %SYMBOLS-FILENAME% +// Purpose: Symbols file +// Author: %AUTHOR% +// Modified by: +// Created: %DATE% +// RCS-ID: +// Copyright: %COPYRIGHT% +// Licence: +///////////////////////////////////////////////////////////////////////////// + +" + "<All platforms>" + "" + "" + 0 + 0 + 0 + 0 + 0 + "" + 0 + 4 + 0 + 1 + 0 + "utf-8" + "" + "AppResources" + "app_resources.h" + "app_resources.cpp" + "" + "" + "utf-8" + "2.9.2" + 0 + "" + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + "Saleem EDAH-TALLY" + " " + 1 + "utf-8" + "" + 0 + 1 + 0 +
+ + + "" + "data-document" + "" + "" + 0 + 1 + 0 + 0 + + "Debug" + "%AUTO%" + "%AUTO%" + "" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "" + "%AUTO%" + 1 + 1 + "%EXECUTABLE%" + "%AUTO%" + "%AUTO%" + "" + "GUI" + "" + "%AUTO%" + 0 + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%AUTO%" + 0 + "%AUTO%" + 4286447616 + "Modular" + "%AUTO%" + "%AUTO%" + "%AUTO%" + 1 + "%AUTO%" + "%AUTO%" + "Default" + "" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "Dynamic" + "Static" + 0 + "" + "Configurations" + 0 + "wxGTK+2" + "config-data-document" + "Unicode" + "Yes" + "No" + "No" + "Yes" + "Yes" + "No" + "Yes" + "builtin" + "Yes" + "Yes" + "Yes" + "Yes" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%AUTO%" + "%WXVERSION%" + + + + + + + "Projects" + "root-document" + "" + "project" + 1 + 1 + 0 + 1 + + "Windows" + "html-document" + "" + "dialogsfolder" + 1 + 1 + 0 + 1 + + "wbDialogProxy" + "Standard" + 10000 + "" + "dialog" + "" + "" + "itemPanel1" + 0 + 0 + 1 + 0 + "" + "wxPanel" + 1 + "StampWidget" + "" + "" + "" + "" + "" + "" + 0 + 1 + "" + 1 + "" + "" + "StampWidget.h" + 300 + "" + 0 + "" + "ID_STAMPWIDGET" + 10000 + "StampWidget.cpp" + "<Any platform>" + "" + "Tiled" + "StampWidget" + "" + 400 + "wxPanel" + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + -1 + "" + -1 + "StampWidget" + 0 + "dialog-document" + 0 + 0 + 0 + 0 + + "wbBoxSizerProxy" + "" + "sizer" + "itemBoxSizer1" + 0 + 0 + 1 + "szStampWidgetMain" + "Vertical" + "<Any platform>" + 0 + 0 + 0 + 0 + "wxBoxSizer V" + 0 + "dialog-control-document" + + "wbTextCtrlProxy" + "" + "textctrl" + "itemTextCtrl2" + 0 + 0 + 1 + "Expand" + "Centre" + "" + "wxTextCtrl" + 5 + "wxTextCtrl" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_TEXTCTRL" + 10001 + "" + "" + 0 + "txtStamp" + "" + "<Any platform>" + 0 + 0 + "Create a stamp with this text, which can be multiline. + +CTRL + S: save the current text. +CTRL + R: restore the saved text." + -1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxTextCtrl: ID_TEXTCTRL" + 0 + "dialog-control-document" + + + "wbBoxSizerProxy" + "" + "sizer" + "itemBoxSizer2" + 0 + 0 + 1 + "Left" + "Centre" + 5 + "szStampWidgetH0" + "Horizontal" + "<Any platform>" + 0 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + "wxBoxSizer H" + 0 + "dialog-control-document" + + "wbFlexGridSizerProxy" + "" + "sizer" + "itemFlexGridSizer3" + 0 + 0 + 1 + "Expand" + "Expand" + 5 + 2 + 0 + "" + "" + "szStampWidgetFlexGrid" + "<Any platform>" + 0 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + "wxFlexGridSizer" + 0 + "dialog-control-document" + + "wbStaticTextProxy" + "" + "statictext" + "itemStaticText4" + 0 + 0 + 1 + "Left" + "Centre" + "" + "wxStaticText" + 5 + "wxStaticText" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_STATIC_FOREGROUND_COLOUR" + 10008 + "" + "Foreground:" + "lblForegroundColour" + "" + "<Any platform>" + 0 + 0 + "" + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxStaticText: ID_STATIC_FOREGROUND_COLOUR" + 0 + "dialog-control-document" + + + "wbColourPickerCtrlProxy" + "" + "dialogcontrol" + "itemColourPickerCtrl5" + 0 + 0 + 1 + "Left" + "Centre" + "" + "wxColourPickerCtrl" + 5 + "wxColourPickerCtrl" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_COLOURCTRL_FOREGROUND" + 10003 + "" + "cpkForegroundStamp" + "" + "<Any platform>" + 0 + 0 + "Foreground colour of the text." + -1 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxColourPickerCtrl: ID_COLOURCTRL_FOREGROUND" + 0 + "dialog-control-document" + + + "wbStaticTextProxy" + "" + "statictext" + "itemStaticText6" + 0 + 0 + 1 + "Left" + "Centre" + "" + "wxStaticText" + 5 + "wxStaticText" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_STATIC_BACKGROUND_COLOUR" + 10009 + "" + "Background:" + "lblBackgroundColour" + "" + "<Any platform>" + 0 + 0 + "" + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxStaticText: ID_STATIC_BACKGROUND_COLOUR" + 0 + "dialog-control-document" + + + "wbColourPickerCtrlProxy" + "" + "dialogcontrol" + "itemColourPickerCtrl7" + 0 + 0 + 1 + "Left" + "Centre" + "" + "wxColourPickerCtrl" + 5 + "wxColourPickerCtrl" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "FFFFFF" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_COLOURCTRL_BACKGROUND" + 10006 + "" + "cpkBackgroundStamp" + "" + "<Any platform>" + 0 + 0 + "Background colour of the text." + -1 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxColourPickerCtrl: ID_COLOURCTRL_BACKGROUND" + 0 + "dialog-control-document" + + + "wbStaticTextProxy" + "" + "statictext" + "itemStaticText8" + 0 + 0 + 1 + "Left" + "Centre" + "" + "wxStaticText" + 5 + "wxStaticText" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_STATIC_LOCATION" + 10010 + "" + "Location:" + "lblLocation" + "" + "<Any platform>" + 0 + 0 + "" + -1 + -1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxStaticText: ID_STATIC_LOCATION" + 0 + "dialog-control-document" + + + "wbComboBoxProxy" + "" + "combobox" + "itemComboBox9" + 0 + 0 + 1 + "Centre" + "Centre" + "" + "wxComboBox" + 5 + "wxComboBox" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_COMBOBOX" + 10005 + "" + "" + "cmbStampLocation" + "" + "<Any platform>" + 0 + 0 + "" + "Location of the stamp on the output." + -1 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + -1 + -1 + "wxComboBox: ID_COMBOBOX" + 0 + "dialog-control-document" + + + + "wbPanelProxy" + "" + "panel" + "itemPanel2" + 0 + 0 + 1 + "Centre" + "Top" + 0 + "" + "wxPanel" + 5 + "wxPanel" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + "" + 1 + 1 + "" + "" + "" + 200 + "" + 0 + "ID_PANEL_BITMAP_PREVIEW" + 10011 + "" + "panBitmapPreview" + "" + "<Any platform>" + 0 + 0 + "" + "Tiled" + "Click to update the preview." + 200 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 1 + -1 + -1 + "wxPanel: ID_PANEL_BITMAP_PREVIEW" + 0 + "dialog-control-document" + + "wbBoxSizerProxy" + "" + "sizer" + "itemBoxSizer4" + 0 + 0 + 1 + "Centre" + "Centre" + 5 + "szBitmapPreviewInPanel" + "Vertical" + "<Any platform>" + 0 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + "wxBoxSizer V" + 0 + "dialog-control-document" + + + + + "wbBoxSizerProxy" + "" + "sizer" + "itemBoxSizer3" + 0 + 0 + 1 + "Expand" + "Centre" + 5 + "szStampWidgetH1" + "Horizontal" + "<Any platform>" + 0 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + "wxBoxSizer H" + 0 + "dialog-control-document" + + "wbFontPickerCtrlProxy" + "" + "dialogcontrol" + "itemFontPickerCtrl4" + 0 + 0 + 1 + "Centre" + "Expand" + "" + "wxFontPickerCtrl" + 5 + "wxFontPickerCtrl" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_FONTCTRL" + 10002 + "" + "fpkStamp" + "" + "<Any platform>" + 0 + 1 + "Select the font of the stamp text." + -1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxFontPickerCtrl: ID_FONTCTRL" + 0 + "dialog-control-document" + + + "wbToggleButtonProxy" + "" + "togglebutton" + "itemToggleButton1" + 0 + 0 + 1 + "Centre" + "Expand" + "" + "wxToggleButton" + 5 + "wxToggleButton" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_TOGGLE_TRANSPARENT" + 10007 + "" + 1 + "Transparent" + "tglTransparent" + "" + "<Any platform>" + 0 + 0 + "Check for a completely transparent background and for a transparent text." + -1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + -1 + -1 + "wxToggleButton: ID_TOGGLE_TRANSPARENT" + 0 + "dialog-control-document" + + + + "wbSliderProxy" + "" + "slider" + "itemSlider6" + 0 + 0 + 1 + "Expand" + "Centre" + "" + "wxSlider" + 5 + "wxSlider" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_SLIDER" + 10004 + "" + 45 + 180 + "sldTextRotationAngle" + -180 + "" + "<Any platform>" + 0 + 0 + "Select the rotation angle of the stamp text." + -1 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + -1 + -1 + "wxSlider: ID_SLIDER" + 0 + "dialog-control-document" + + + + + "wbDialogProxy" + "Standard" + 10000 + "" + "dialog" + "" + "" + "itemPanel1" + 0 + 0 + 1 + 0 + "" + "wxPanel" + 1 + "StampWidgets" + "" + "" + "" + "" + "" + "" + 0 + 1 + "" + 0 + "" + "" + "StampWidgets.h" + 300 + "" + 0 + "" + "ID_STAMPWIDGETS" + 10000 + "StampWidgets.cpp" + "<Any platform>" + "" + "Tiled" + "StampWidgets" + "" + 400 + "wxPanel" + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + -1 + "" + -1 + "StampWidgets" + 0 + "dialog-document" + 0 + 0 + 0 + 0 + + "wbBoxSizerProxy" + "" + "sizer" + "itemBoxSizer1" + 0 + 0 + 1 + "Centre" + "Centre" + 5 + "szNoteBookMain" + "Horizontal" + "<Any platform>" + 0 + 0 + 1 + 0 + 1 + 0 + 1 + 0 + 1 + "wxBoxSizer H" + 0 + "dialog-control-document" + + "wbBoxSizerProxy" + "" + "sizer" + "itemBoxSizer2" + 0 + 0 + 1 + "Centre" + "Top" + 5 + "szNoteBookButtons" + "Horizontal" + "<Any platform>" + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + "wxBoxSizer H" + 0 + "dialog-control-document" + + "wbButtonProxy" + "" + "dialogcontrol" + "itemButton3" + 0 + 0 + 1 + "Centre" + "Centre" + "" + "wxButton" + 1 + "wxButton" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 0 + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_BUTTON_NB" + 10002 + "" + "+" + "btnAddStampWidget" + "" + "<Any platform>" + 0 + 0 + "Add a stamp widget." + 30 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + -1 + "wxButton: ID_BUTTON_NB" + 0 + "dialog-control-document" + + + "wbButtonProxy" + "" + "dialogcontrol" + "itemButton4" + 0 + 0 + 1 + "Centre" + "Centre" + "" + "wxButton" + 1 + "wxButton" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 0 + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_BUTTON_NB1" + 10003 + "" + "-" + "btnDeleteStampWidget" + "" + "<Any platform>" + 0 + 0 + "Remove the selected stamp widget." + 30 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + -1 + -1 + "wxButton: ID_BUTTON_NB1" + 0 + "dialog-control-document" + + + + "wbNotebookProxy" + "" + "notebook" + "itemNotebook5" + 0 + 0 + 1 + "Centre" + "Expand" + "" + "wxNotebook" + 5 + "wxNotebook" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + 1 + 1 + "" + "" + "" + -1 + "" + 0 + "ID_NOTEBOOK_STAMPWIDGETS_" + 10001 + "" + "nbStampWidgets" + "" + 0 + "<Any platform>" + 0 + 1 + "" + -1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + -1 + -1 + "wxNotebook: ID_NOTEBOOK_STAMPWIDGETS_" + 0 + "dialog-control-document" + + + + + + "Sources" + "html-document" + "" + "sourcesfolder" + 1 + 1 + 0 + 1 + + "StampWidget.rc" + "source-editor-document" + "StampWidget.rc" + "source-editor" + 0 + 0 + 1 + 0 + "15/6/2025" + "" + + + + "Images" + "html-document" + "" + "bitmapsfolder" + 1 + 1 + 0 + 1 + + + + +
diff --git a/Resources/StampWidget/UI/StampWidget.rc b/Resources/StampWidget/UI/StampWidget.rc new file mode 100644 index 0000000..b86c4e2 --- /dev/null +++ b/Resources/StampWidget/UI/StampWidget.rc @@ -0,0 +1 @@ +#include "wx/msw/wx.rc" diff --git a/Resources/StampWidget/UI/StampWidgets.cpp b/Resources/StampWidget/UI/StampWidgets.cpp new file mode 100644 index 0000000..570d0c6 --- /dev/null +++ b/Resources/StampWidget/UI/StampWidgets.cpp @@ -0,0 +1,178 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: StampWidgets.cpp +// Purpose: +// Author: Saleem EDAH-TALLY +// Modified by: +// Created: dim. 06 juil. 2025 22:33:34 +// RCS-ID: +// Copyright: Copyright Saleem EDAH-TALLY. All rights reserved. +// Licence: +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +////@begin includes +#include "wx/imaglist.h" +////@end includes + +#include "StampWidgets.h" + +////@begin XPM images +////@end XPM images + + +/* + * StampWidgets type definition + */ + +IMPLEMENT_DYNAMIC_CLASS( StampWidgets, wxPanel ) + + +/* + * StampWidgets event table definition + */ + +BEGIN_EVENT_TABLE( StampWidgets, wxPanel ) + +////@begin StampWidgets event table entries +////@end StampWidgets event table entries + +END_EVENT_TABLE() + + +/* + * StampWidgets constructors + */ + +StampWidgets::StampWidgets() +{ + Init(); +} + +StampWidgets::StampWidgets( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) +{ + Init(); + Create(parent, id, pos, size, style); +} + + +/* + * StampWidgets creator + */ + +bool StampWidgets::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style ) +{ +////@begin StampWidgets creation + SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY); + wxPanel::Create( parent, id, pos, size, style ); + + CreateControls(); + Centre(); +////@end StampWidgets creation + return true; +} + + +/* + * StampWidgets destructor + */ + +StampWidgets::~StampWidgets() +{ +////@begin StampWidgets destruction +////@end StampWidgets destruction +} + + +/* + * Member initialisation + */ + +void StampWidgets::Init() +{ +////@begin StampWidgets member initialisation + szNoteBookMain = NULL; + szNoteBookButtons = NULL; + btnAddStampWidget = NULL; + btnDeleteStampWidget = NULL; + nbStampWidgets = NULL; +////@end StampWidgets member initialisation +} + + +/* + * Control creation for StampWidgets + */ + +void StampWidgets::CreateControls() +{ +////@begin StampWidgets content construction + StampWidgets* itemPanel1 = this; + + szNoteBookMain = new wxBoxSizer(wxHORIZONTAL); + itemPanel1->SetSizer(szNoteBookMain); + + szNoteBookButtons = new wxBoxSizer(wxHORIZONTAL); + szNoteBookMain->Add(szNoteBookButtons, 0, wxALIGN_TOP, 5); + + btnAddStampWidget = new wxButton( itemPanel1, ID_BUTTON_NB, _("+"), wxDefaultPosition, wxSize(30, -1), 0 ); + if (StampWidgets::ShowToolTips()) + btnAddStampWidget->SetToolTip(_("Add a stamp widget.")); + szNoteBookButtons->Add(btnAddStampWidget, 0, wxALIGN_CENTER_VERTICAL|wxFIXED_MINSIZE, 1); + + btnDeleteStampWidget = new wxButton( itemPanel1, ID_BUTTON_NB1, _("-"), wxDefaultPosition, wxSize(30, -1), 0 ); + if (StampWidgets::ShowToolTips()) + btnDeleteStampWidget->SetToolTip(_("Remove the selected stamp widget.")); + szNoteBookButtons->Add(btnDeleteStampWidget, 0, wxALIGN_CENTER_VERTICAL, 1); + + nbStampWidgets = new wxNotebook( itemPanel1, ID_NOTEBOOK_STAMPWIDGETS_, wxDefaultPosition, wxDefaultSize, wxBK_DEFAULT ); + + szNoteBookMain->Add(nbStampWidgets, 1, wxGROW|wxALL, 5); + +////@end StampWidgets content construction +} + + +/* + * Should we show tooltips? + */ + +bool StampWidgets::ShowToolTips() +{ + return true; +} + +/* + * Get bitmap resources + */ + +wxBitmap StampWidgets::GetBitmapResource( const wxString& name ) +{ + // Bitmap retrieval +////@begin StampWidgets bitmap retrieval + wxUnusedVar(name); + return wxNullBitmap; +////@end StampWidgets bitmap retrieval +} + +/* + * Get icon resources + */ + +wxIcon StampWidgets::GetIconResource( const wxString& name ) +{ + // Icon retrieval +////@begin StampWidgets icon retrieval + wxUnusedVar(name); + return wxNullIcon; +////@end StampWidgets icon retrieval +} diff --git a/Resources/StampWidget/UI/StampWidgets.h b/Resources/StampWidget/UI/StampWidgets.h new file mode 100644 index 0000000..58d6a18 --- /dev/null +++ b/Resources/StampWidget/UI/StampWidgets.h @@ -0,0 +1,103 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: StampWidgets.h +// Purpose: +// Author: Saleem EDAH-TALLY +// Modified by: +// Created: dim. 06 juil. 2025 22:33:34 +// RCS-ID: +// Copyright: Copyright Saleem EDAH-TALLY. All rights reserved. +// Licence: +///////////////////////////////////////////////////////////////////////////// + +#ifndef _STAMPWIDGETS_H_ +#define _STAMPWIDGETS_H_ + + +/*! + * Includes + */ + +////@begin includes +#include "wx/notebook.h" +////@end includes + +/*! + * Forward declarations + */ + +////@begin forward declarations +class wxBoxSizer; +class wxNotebook; +////@end forward declarations +#include +#include +/*! + * Control identifiers + */ + +////@begin control identifiers +#define ID_STAMPWIDGETS 10000 +#define ID_BUTTON_NB 10002 +#define ID_BUTTON_NB1 10003 +#define ID_NOTEBOOK_STAMPWIDGETS_ 10001 +#define SYMBOL_STAMPWIDGETS_STYLE wxTAB_TRAVERSAL +#define SYMBOL_STAMPWIDGETS_TITLE _("StampWidgets") +#define SYMBOL_STAMPWIDGETS_IDNAME ID_STAMPWIDGETS +#define SYMBOL_STAMPWIDGETS_SIZE wxSize(400, 300) +#define SYMBOL_STAMPWIDGETS_POSITION wxDefaultPosition +////@end control identifiers + + +/*! + * StampWidgets class declaration + */ + +class StampWidgets: public wxPanel +{ + DECLARE_DYNAMIC_CLASS( StampWidgets ) + DECLARE_EVENT_TABLE() + +public: + /// Constructors + StampWidgets(); + StampWidgets( wxWindow* parent, wxWindowID id = SYMBOL_STAMPWIDGETS_IDNAME, const wxPoint& pos = SYMBOL_STAMPWIDGETS_POSITION, const wxSize& size = SYMBOL_STAMPWIDGETS_SIZE, long style = SYMBOL_STAMPWIDGETS_STYLE ); + + /// Creation + bool Create( wxWindow* parent, wxWindowID id = SYMBOL_STAMPWIDGETS_IDNAME, const wxPoint& pos = SYMBOL_STAMPWIDGETS_POSITION, const wxSize& size = SYMBOL_STAMPWIDGETS_SIZE, long style = SYMBOL_STAMPWIDGETS_STYLE ); + + /// Destructor + ~StampWidgets(); + + /// Initialises member variables + void Init(); + + /// Creates the controls and sizers + void CreateControls(); + +////@begin StampWidgets event handler declarations + +////@end StampWidgets event handler declarations + +////@begin StampWidgets member function declarations + + /// Retrieves bitmap resources + wxBitmap GetBitmapResource( const wxString& name ); + + /// Retrieves icon resources + wxIcon GetIconResource( const wxString& name ); +////@end StampWidgets member function declarations + + /// Should we show tooltips? + static bool ShowToolTips(); + +////@begin StampWidgets member variables + wxBoxSizer* szNoteBookMain; + wxBoxSizer* szNoteBookButtons; + wxButton* btnAddStampWidget; + wxButton* btnDeleteStampWidget; + wxNotebook* nbStampWidgets; +////@end StampWidgets member variables +}; + +#endif + // _STAMPWIDGETS_H_ diff --git a/Resources/StampWidget/XStampWidget.cpp b/Resources/StampWidget/XStampWidget.cpp new file mode 100644 index 0000000..172d63c --- /dev/null +++ b/Resources/StampWidget/XStampWidget.cpp @@ -0,0 +1,230 @@ +// /* +// * File: XStampWidget.cpp +// * Author: Saleem Edah-Tally - nmset@yandex.com +// * License : CeCILL-C +// * Copyright Saleem Edah-Tally - © 2025 +// * +// * Created on 01 07 2025, 20:35 +// */ + +#include "XStampWidget.h" +#include "DefsStampWidget.h" +#include "StampWorker.h" +#include + +using namespace std; + +IMPLEMENT_CLASS( XStampWidget, StampWidget ) + +XStampWidget::XStampWidget(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) +: StampWidget(parent, id, pos, size, style) +{} + +bool XStampWidget::Setup(wxConfig * config) +{ + m_config = config; + if (!m_config) + return false; + + const wxString fontDesc = m_config->Read("/Stamp/FontDesc", ""); + if (!fontDesc.IsEmpty()) + { + wxFont font = wxNullFont; + font.SetNativeFontInfo(fontDesc); + if (font.IsOk()) + { + fpkStamp->SetSelectedFont(font); + fpkStamp->Update(); + } + } + long rgb = m_config->Read("/Stamp/ForegroundRGB", wxNOT_FOUND); + if (rgb > wxNOT_FOUND) + { + wxColour foregroundColour = wxNullColour; + foregroundColour.SetRGB((wxUint32) rgb); + if (foregroundColour.IsOk()) + { + cpkForegroundStamp->SetColour(foregroundColour); + } + } + rgb = m_config->Read("/Stamp/BackgroundRGB", wxNOT_FOUND); + if (rgb > wxNOT_FOUND) + { + wxColour backgroundColour = wxNullColour; + backgroundColour.SetRGB((wxUint32) rgb); + if (backgroundColour.IsOk()) + { + cpkBackgroundStamp->SetColour(backgroundColour); + } + } + int textRotationAngle = m_config->Read("/Stamp/RotationAngle", 45); + sldTextRotationAngle->SetValue(textRotationAngle); + bool transparency = m_config->ReadBool("/Stamp/Transparency", true); + tglTransparent->SetValue(transparency); + wxCommandEvent evt; + evt.SetInt(transparency); + OnTransparencyToggled(evt); + + fpkStamp->Bind(wxEVT_FONTPICKER_CHANGED, &XStampWidget::OnFontChanged, this); + cpkForegroundStamp->Bind(wxEVT_COLOURPICKER_CHANGED, &XStampWidget::OnForegroundColourChanged, this); + cpkBackgroundStamp->Bind(wxEVT_COLOURPICKER_CHANGED, &XStampWidget::OnBackgroundColourChanged, this); + // *End* of any mouse and any keyboard interaction. + sldTextRotationAngle->Bind(wxEVT_SCROLL_CHANGED, &XStampWidget::OnAngleSliderChanged, this); + txtStamp->Bind(wxEVT_KEY_UP, &XStampWidget::OnTxtKeyPressed, this); + tglTransparent->Bind(wxEVT_TOGGLEBUTTON, &XStampWidget::OnTransparencyToggled, this); + + wxArrayString stampLocations ({_("Centre"), + _("North"), _("South"), _("East"), _("West"), + _("North-east"), _("North-west"), + _("South-east"), _("South-west")}); + cmbStampLocation->Append(stampLocations); + int location = m_config->Read("/Stamp/Location", wxNOT_FOUND); + cmbStampLocation->Select((location >= cmbStampLocation->GetCount() || location < 0) ? 0 : location); + cmbStampLocation->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &XStampWidget::OnLocationChanged, this); + + // A panel container is used to have its borders. + m_sbmpPreview = new wxGenericStaticBitmap(panBitmapPreview, wxID_ANY, wxBitmapBundle(wxNullBitmap), wxDefaultPosition, panBitmapPreview->GetSize()); + szBitmapPreviewInPanel->Add(m_sbmpPreview, 0, wxGROW | wxALL, 5); + m_sbmpPreview->SetScaleMode(wxStaticBitmapBase::Scale_AspectFit); + + m_sbmpPreview->Bind(wxEVT_LEFT_UP, &XStampWidget::OnBitmapPreview, this); + return true; +} + +void XStampWidget::OnFontChanged(wxFontPickerEvent& evt) +{ + if (!m_config) + { + evt.Skip(); + return; + } + const wxString desc = evt.GetFont().GetNativeFontInfoDesc(); + m_config->Write("/Stamp/FontDesc", desc); + m_config->Flush(); + + evt.Skip(); +} + +void XStampWidget::OnForegroundColourChanged(wxColourPickerEvent& evt) +{ + if (!m_config) + { + evt.Skip(); + return; + } + const wxUint32 rgb = evt.GetColour().GetRGB(); + m_config->Write("/Stamp/ForegroundRGB", (long) rgb); + m_config->Flush(); + + evt.Skip(); +} + +void XStampWidget::OnBackgroundColourChanged(wxColourPickerEvent& evt) +{ + if (!m_config) + { + evt.Skip(); + return; + } + const wxUint32 rgb = evt.GetColour().GetRGB(); + m_config->Write("/Stamp/BackgroundRGB", (long) rgb); + m_config->Flush(); + + evt.Skip(); +} + +void XStampWidget::OnAngleSliderChanged(wxScrollEvent& evt) +{ + if (!m_config) + { + evt.Skip(); + return; + } + m_config->Write("/Stamp/RotationAngle", evt.GetInt()); + m_config->Flush(); + evt.Skip(); +} + +void XStampWidget::OnTxtKeyPressed(wxKeyEvent& evt) +{ + if (!m_config || !evt.ControlDown()) + { + evt.Skip(); + return; + } + if (evt.GetKeyCode() == 'S') + { + if (txtStamp->IsEmpty()) + { + evt.Skip(); + return; + } + m_config->Write("/Stamp/Text", txtStamp->GetValue()); + m_config->Flush(); + } + else if (evt.GetKeyCode() == 'R') + { + wxString last; + if (m_config->Read("/Stamp/Text", &last)) + { + txtStamp->SetValue(last); + txtStamp->SetSelection(last.Len(), last.Len()); + } + } + + evt.Skip(); +} + +void XStampWidget::OnLocationChanged(wxCommandEvent& evt) +{ + if (!m_config) + { + evt.Skip(); + return; + } + m_config->Write("/Stamp/Location", evt.GetSelection()); + m_config->Flush(); + evt.Skip(); +} + +void XStampWidget::OnTransparencyToggled(wxCommandEvent& evt) +{ + lblBackgroundColour->Show(evt.GetInt() == 0); + cpkBackgroundStamp->Show(evt.GetInt() == 0); + if (GetSizer()) + GetSizer()->Layout(); + + if (!m_config) + { + evt.Skip(); + return; + } + m_config->Write("/Stamp/Transparency", evt.GetInt()); + m_config->Flush(); + evt.Skip(); +} + + +StampDescriptor * XStampWidget::GetStampDescriptor() +{ + m_descriptor.reset(nullptr); + m_descriptor = std::make_unique (); + m_descriptor->text = txtStamp->GetValue(); + m_descriptor->font = fpkStamp->GetSelectedFont(); + m_descriptor->foregroundColour = cpkForegroundStamp->GetColour(); + m_descriptor->backgroundColour = cpkBackgroundStamp->GetColour(); + m_descriptor->rotationAngle = sldTextRotationAngle->GetValue(); + m_descriptor->location = cmbStampLocation->GetSelection(); + m_descriptor->transparent = tglTransparent->GetValue(); + // Not setting image, it is to be created. + return m_descriptor.get(); +} + +void XStampWidget::OnBitmapPreview(wxMouseEvent& evt) +{ + StampDescriptor * descriptor = GetStampDescriptor(); + wxImage preview = StampWorker::CreateStamp(descriptor, 72); + m_sbmpPreview->SetBitmap(wxBitmapBundle(preview)); + GetSizer()->Layout(); + evt.Skip(); +} diff --git a/Resources/StampWidget/XStampWidget.h b/Resources/StampWidget/XStampWidget.h new file mode 100644 index 0000000..3fb76fd --- /dev/null +++ b/Resources/StampWidget/XStampWidget.h @@ -0,0 +1,52 @@ +// /* +// * File: XStampWidget.h +// * Author: Saleem Edah-Tally - nmset@yandex.com +// * License : CeCILL-C +// * Copyright Saleem Edah-Tally - © 2025 +// * +// * Created on 01 07 2025, 20:35 +// */ + +#ifndef XSTAMPWIDGET_H +#define XSTAMPWIDGET_H + +#include "StampWidget.h" +#include +#include +#include + +struct StampDescriptor; + +/** + * This widget collects inputs for the creation of a stamp on scan pages.\n + * - text + * - font + * - foreground colour + * - background colour + * - angle of rotation + * - transparency. + */ +class XStampWidget : public StampWidget +{ + DECLARE_DYNAMIC_CLASS( XStampWidget ) +public: + XStampWidget( wxWindow* parent, wxWindowID id = SYMBOL_STAMPWIDGET_IDNAME, const wxPoint& pos = SYMBOL_STAMPWIDGET_POSITION, const wxSize& size = SYMBOL_STAMPWIDGET_SIZE, long style = SYMBOL_STAMPWIDGET_STYLE ); + + bool Setup(wxConfig * config); + StampDescriptor * GetStampDescriptor(); +private: + wxConfig * m_config; + std::unique_ptr m_descriptor; + wxGenericStaticBitmap * m_sbmpPreview; + + void OnFontChanged(wxFontPickerEvent& evt); + void OnForegroundColourChanged(wxColourPickerEvent& evt); + void OnBackgroundColourChanged(wxColourPickerEvent& evt); + void OnAngleSliderChanged(wxScrollEvent& evt); + void OnTxtKeyPressed ( wxKeyEvent& evt ); + void OnLocationChanged(wxCommandEvent& evt); + void OnTransparencyToggled(wxCommandEvent& evt); + void OnBitmapPreview(wxMouseEvent& evt); +}; + +#endif // XSTAMPWIDGET_H diff --git a/Resources/StampWidget/XStampWidgets.cpp b/Resources/StampWidget/XStampWidgets.cpp new file mode 100644 index 0000000..f6118a7 --- /dev/null +++ b/Resources/StampWidget/XStampWidgets.cpp @@ -0,0 +1,88 @@ +// /* +// * File: XStampWidgets.cpp +// * Author: Saleem Edah-Tally - nmset@yandex.com +// * License : CeCILL-C +// * Copyright Saleem Edah-Tally - © 2025 +// * +// * Created on 06 07 2025, 22:41 +// */ + +#include "XStampWidgets.h" +#include +#include + +IMPLEMENT_CLASS( XStampWidgets, StampWidgets ) + +XStampWidgets::XStampWidgets(wxWindow* parent, wxWindowID id, const wxPoint& pos, + const wxSize& size, long style) +: StampWidgets(parent, id, pos, size, style) +{} + +bool XStampWidgets::Setup(wxFileConfig* config) +{ + m_config = config; + if (!m_config) + return false; + + wxMouseEvent evt; + AddStampWidget(evt); + btnAddStampWidget->Bind(wxEVT_LEFT_UP, &XStampWidgets::AddStampWidget, this); + btnDeleteStampWidget->Bind(wxEVT_LEFT_UP, &XStampWidgets::DeleteStampWidget, this); + return true; +} + +void XStampWidgets::AddStampWidget(wxMouseEvent& evt) +{ + XStampWidget * stampWidget = new XStampWidget(nbStampWidgets); + stampWidget->Setup(m_config); + stampWidget->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &XStampWidgets::OnStampLocationChanged, this); + nbStampWidgets->AddPage(stampWidget, stampWidget->cmbStampLocation->GetStringSelection(), true); + if (GetParent()->GetSizer()) + GetParent()->GetSizer()->Layout(); + + evt.Skip(); +} + +void XStampWidgets::DeleteStampWidget(wxMouseEvent& evt) +{ + int selectedPage = nbStampWidgets->GetSelection(); + if (selectedPage == wxNOT_FOUND) + { + evt.Skip(); + return; + } + nbStampWidgets->DeletePage(selectedPage); + evt.Skip(); +} + +std::vector * XStampWidgets::GetStampDescriptors() +{ + m_stampDescriptors.clear(); // Stored as unique_ptr in XStampWidget. + for (uint i = 0; i < nbStampWidgets->GetPageCount(); i++) + { + XStampWidget * stampWidget = static_cast (nbStampWidgets->GetPage(i)); + if (stampWidget) + { + m_stampDescriptors.push_back(stampWidget->GetStampDescriptor()); + } + } + return &m_stampDescriptors; +} + +void XStampWidgets::OnStampLocationChanged(wxCommandEvent& evt) +{ + int selectedPage = nbStampWidgets->GetSelection(); + if (selectedPage == wxNOT_FOUND) + { + evt.Skip(); + return; + } + XStampWidget * stampWidget = static_cast (nbStampWidgets->GetPage(selectedPage)); + if (!stampWidget) + { + evt.Skip(); + return; + } + nbStampWidgets->SetPageText(selectedPage, stampWidget->cmbStampLocation->GetStringSelection()); + evt.Skip(); +} diff --git a/Resources/StampWidget/XStampWidgets.h b/Resources/StampWidget/XStampWidgets.h new file mode 100644 index 0000000..6a9a5bd --- /dev/null +++ b/Resources/StampWidget/XStampWidgets.h @@ -0,0 +1,41 @@ +// /* +// * File: XStampWidgets.h +// * Author: Saleem Edah-Tally - nmset@yandex.com +// * License : CeCILL-C +// * Copyright Saleem Edah-Tally - © 2025 +// * +// * Created on 06 07 2025, 22:41 +// */ + +#ifndef XSTAMPWIDGETS_H +#define XSTAMPWIDGETS_H + +#include "StampWidgets.h" +#include +#include +#include +#include + +struct StampDescriptor; + +class XStampWidgets : public StampWidgets +{ + DECLARE_DYNAMIC_CLASS( XStampWidgets ) +public: + XStampWidgets(wxWindow* parent, wxWindowID id = SYMBOL_STAMPWIDGETS_IDNAME, + const wxPoint& pos = SYMBOL_STAMPWIDGETS_POSITION, + const wxSize& size = SYMBOL_STAMPWIDGETS_SIZE, + long style = SYMBOL_STAMPWIDGETS_STYLE); + bool Setup(wxConfig * config); + std::vector * GetStampDescriptors(); + +private: + wxConfig * m_config; + std::vector m_stampDescriptors; + + void AddStampWidget(wxMouseEvent& evt); + void DeleteStampWidget(wxMouseEvent& evt); + void OnStampLocationChanged(wxCommandEvent& evt); +}; + +#endif // XSTAMPWIDGETS_H diff --git a/Resources/UI/S7/S7.pjd b/Resources/UI/S7/S7.pjd index 09633ce..108c3ae 100644 --- a/Resources/UI/S7/S7.pjd +++ b/Resources/UI/S7/S7.pjd @@ -419,7 +419,7 @@ 1 0 1 - "wxBoxSizer V" + "wxBoxSizer V: szMain" 0 "dialog-control-document" @@ -526,7 +526,7 @@ Double-click to go to the selected directory."
-1 "Basename" 0 - "ID_TEXTCTRL" + "ID_TEXTCTRL_S7" 10003 "" "" @@ -576,7 +576,7 @@ Double-click to go to the selected directory."
0 -1 -1 - "wxTextCtrl: ID_TEXTCTRL" + "wxTextCtrl: ID_TEXTCTRL_S7" 0 "dialog-control-document" diff --git a/Resources/UI/S7/s7.cpp b/Resources/UI/S7/s7.cpp index 1bf37a3..695dd3a 100644 --- a/Resources/UI/S7/s7.cpp +++ b/Resources/UI/S7/s7.cpp @@ -126,7 +126,7 @@ void S7::CreateControls() dpkDestination->SetToolTip(_("Select a destination directory.\nDouble-click to go to the selected directory.")); szMain->Add(dpkDestination, 0, wxGROW|wxALL, 5); - txtBasename = new wxTextCtrl( panMain, ID_TEXTCTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + txtBasename = new wxTextCtrl( panMain, ID_TEXTCTRL_S7, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); txtBasename->SetHelpText(_("Basename")); if (S7::ShowToolTips()) txtBasename->SetToolTip(_("Specify a destination file basename (without extension).\n\n'CTRL + click' for about information.")); diff --git a/Resources/UI/S7/s7.h b/Resources/UI/S7/s7.h index f69647a..cf9ad7c 100644 --- a/Resources/UI/S7/s7.h +++ b/Resources/UI/S7/s7.h @@ -39,7 +39,7 @@ class wxDirPickerCtrl; #define ID_S7 10000 #define ID_PANEL 10001 #define ID_DIRPICKERCTRL 10002 -#define ID_TEXTCTRL 10003 +#define ID_TEXTCTRL_S7 10003 #define SYMBOL_S7_STYLE wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU|wxCLOSE_BOX #define SYMBOL_S7_TITLE _("S7") #define SYMBOL_S7_IDNAME ID_S7 diff --git a/XS7.cpp b/XS7.cpp index 24c18bc..367da14 100644 --- a/XS7.cpp +++ b/XS7.cpp @@ -17,6 +17,8 @@ using namespace std; +IMPLEMENT_CLASS( XS7, S7 ) + XS7::XS7(wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style) : S7(parent, id, caption, pos, size, style) {} @@ -63,7 +65,8 @@ void XS7::Setup() SetStatusBar(sb); m_insaneWidget = new XInsaneWidget(panMain, sb, m_config.get()); - szMain->Add(m_insaneWidget, 0, wxGROW | wxALL); + m_insaneWidget->Setup(); + szMain->Insert(2, m_insaneWidget, 1, wxGROW | wxALL); dpkDestination->Bind ( wxEVT_DIRPICKER_CHANGED, &XS7::OnDpkRepositoryChange, this ); dpkDestination->GetTextCtrl()->Bind ( wxEVT_LEFT_DCLICK, &XS7::OnDpkDoubleClick, this ); diff --git a/XS7.h b/XS7.h index 35f71c8..a63c978 100644 --- a/XS7.h +++ b/XS7.h @@ -17,6 +17,7 @@ class XS7 : public S7 { + DECLARE_DYNAMIC_CLASS( XS7 ) public: XS7(wxWindow* parent, wxWindowID id = SYMBOL_S7_IDNAME, const wxString& caption = SYMBOL_S7_TITLE, const wxPoint& pos = SYMBOL_S7_POSITION, const wxSize& size = SYMBOL_S7_SIZE, long style = SYMBOL_S7_STYLE ); diff --git a/globals.h b/globals.h index 7dd7423..4a97682 100644 --- a/globals.h +++ b/globals.h @@ -11,7 +11,7 @@ #define GLOBALS_H #define _APPNAME_ "S7" -#define _APPVERSION_ 1 +#define _APPVERSION_ 2 #define _INSANEWIDGET_NAME "InsaneWidget" #endif /* GLOBALS_H */