Add a 'Stamp' widget.

Place one or multiple stamps on scanned pages in defined locations.

A stamp is understood here as
 - a transparent text in a transparent frame with no borders
 - an opaque text on an opaque background with no borders.

Stamp parameters:
 - text
 - font
 - foreground colour
 - background colour
 - angle of rotation
 - transparency.

Locations:
 - centre
 - cardinal directions
 - inter-cardinal directions.
This commit is contained in:
Saleem Edah-Tally
2025-07-01 22:38:07 +02:00
parent c2c792dd3d
commit a2045aa1f6
38 changed files with 3376 additions and 71 deletions

View File

@@ -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}
)

View File

@@ -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.

View File

@@ -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}

View File

@@ -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 <string>
#include <map>
@@ -27,4 +27,4 @@ static void UpdateExtensionsMap()
Extensions[PNM] = "pnm";
}
#endif // COMMON_H
#endif // DEFSINSANEWIDGET_H

View File

@@ -13,7 +13,6 @@
#include <sstream>
#include <fstream>
#include <paper.h>
#include <libinsane/log.h>
#include <libinsane/safebet.h>
#include <libinsane/error.h>
#include <libinsane/util.h>
@@ -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<double, double> br;
if (GetBottomRight(br))
{

View File

@@ -8,14 +8,17 @@
// */
#include "PixelToImageWriter.h"
#include <Common.h>
#include <StampWorker.h>
#include <fstream>
#include <DefsInsaneWidget.h>
#include <DefsStampWidget.h>
using namespace std;
bool PixelToImageWriter::Convert(const std::string& pixelFilePath,
int imageWidth, int imageHeight,
int outputFormat, wxImage * image)
int imageWidth, int imageHeight,
std::vector<StampDescriptor*> * descriptors,
int outputFormat, wxImage * image)
{
UpdateExtensionsMap();
wxImage * outImage = image;
@@ -35,6 +38,16 @@ bool PixelToImageWriter::Convert(const std::string& pixelFilePath,
raw.assign(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
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)
{

View File

@@ -10,19 +10,26 @@
#ifndef PIXELTOIMAGEWRITER_H
#define PIXELTOIMAGEWRITER_H
#include "Common.h"
#include "DefsInsaneWidget.h"
#include <string>
#include <vector>
#include <wx/wx.h>
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<StampDescriptor*> * descriptors,
int outputFormat = PNG, wxImage * image = nullptr);
};
#endif // PIXELTOIMAGEWRITER_H

View File

@@ -9,7 +9,11 @@
#include "PixelToPdfWriter.h"
#include <iostream>
#include <sstream>
#include <memory>
#include <StampWorker.h>
#include <DefsInsaneWidget.h>
#include <DefsStampWidget.h>
using namespace std;
using namespace PoDoFo;
@@ -30,7 +34,8 @@ PixelToPdfWriter::PixelToPdfWriter()
bool PixelToPdfWriter::AddPageAt(const std::string& pixelFile, uint width, uint height, uint index,
PoDoFo::PdfPageSize pageSize, PoDoFo::PdfColorSpace)
std::vector<StampDescriptor*> * 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<char>(ifs), istreambuf_iterator<char>());
if (descriptors)
{
for (StampDescriptor * descriptor : *descriptors)
{
if (!descriptor)
continue;
wxImage background;
background.SetData(reinterpret_cast<unsigned char*> (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();

View File

@@ -12,13 +12,18 @@
#include <string>
#include <map>
#include <vector>
#include <podofo/podofo.h>
#include <wx/wx.h>
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<StampDescriptor*> * descriptors,
PoDoFo::PdfPageSize pageSize = PoDoFo::PdfPageSize::A4,
PoDoFo::PdfColorSpace = PoDoFo::PdfColorSpace::DeviceRGB /*Unused*/);
void Save(const std::string& pdfFile);

View File

@@ -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

View File

@@ -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;

View File

@@ -245,7 +245,7 @@
<string name="proxy-Font">""</string>
<string name="proxy-Foreground colour">""</string>
<string name="proxy-Header filename">"InsaneWidget.h"</string>
<long name="proxy-Height">300</long>
<long name="proxy-Height">-1</long>
<string name="proxy-Help text">""</string>
<bool name="proxy-Hidden">0</bool>
<string name="proxy-Icon">""</string>
@@ -257,7 +257,7 @@
<string name="proxy-Texture style">"Tiled"</string>
<string name="proxy-Title">"InsaneWidget"</string>
<string name="proxy-Tooltip text">""</string>
<long name="proxy-Width">400</long>
<long name="proxy-Width">-1</long>
<string name="proxy-Window kind">"wxPanel"</string>
<bool name="proxy-wxBORDER_THEME">0</bool>
<bool name="proxy-wxCAPTION">0</bool>
@@ -303,13 +303,21 @@
<long name="is-transient">0</long>
<long name="locked">0</long>
<long name="owns-file">1</long>
<string name="proxy-Member variable name">""</string>
<string name="proxy-AlignH">"Centre"</string>
<string name="proxy-AlignV">"Centre"</string>
<long name="proxy-Border">5</long>
<string name="proxy-Member variable name">"szInsaneWidgetMain"</string>
<string name="proxy-Orientation">"Vertical"</string>
<string name="proxy-Platform">"&lt;Any platform&gt;"</string>
<long name="proxy-Stretch factor">0</long>
<bool name="proxy-wxADJUST_MINSIZE">0</bool>
<bool name="proxy-wxBOTTOM">1</bool>
<bool name="proxy-wxFIXED_MINSIZE">0</bool>
<bool name="proxy-wxLEFT">1</bool>
<bool name="proxy-wxRESERVE_SPACE_EVEN_IF_HIDDEN">0</bool>
<bool name="proxy-wxRIGHT">1</bool>
<bool name="proxy-wxSHAPED">0</bool>
<bool name="proxy-wxTOP">1</bool>
<string name="title">"wxBoxSizer V"</string>
<long name="title-mode">0</long>
<string name="type">"dialog-control-document"</string>
@@ -538,7 +546,8 @@
<bool name="proxy-Separate files">0</bool>
<long name="proxy-Stretch factor">0</long>
<string name="proxy-Tooltip text">"'Left click' to start the scan project.
'Right click' to show the scanner widget."</string>
'Right click' to show the scanner widget.
'Ctrl + Right click' to show the Stamp dialog."</string>
<long name="proxy-Width">-1</long>
<bool name="proxy-wxADJUST_MINSIZE">0</bool>
<bool name="proxy-wxBOTTOM">1</bool>
@@ -654,13 +663,21 @@
<long name="is-transient">0</long>
<long name="locked">0</long>
<long name="owns-file">1</long>
<string name="proxy-AlignH">"Centre"</string>
<string name="proxy-AlignV">"Centre"</string>
<long name="proxy-Border">5</long>
<string name="proxy-Member variable name">""</string>
<string name="proxy-Orientation">"Vertical"</string>
<string name="proxy-Platform">"&lt;Any platform&gt;"</string>
<long name="proxy-Stretch factor">0</long>
<bool name="proxy-wxADJUST_MINSIZE">0</bool>
<bool name="proxy-wxBOTTOM">1</bool>
<bool name="proxy-wxFIXED_MINSIZE">0</bool>
<bool name="proxy-wxLEFT">1</bool>
<bool name="proxy-wxRESERVE_SPACE_EVEN_IF_HIDDEN">0</bool>
<bool name="proxy-wxRIGHT">1</bool>
<bool name="proxy-wxSHAPED">0</bool>
<bool name="proxy-wxTOP">1</bool>
<string name="title">"wxBoxSizer V"</string>
<long name="title-mode">0</long>
<string name="type">"dialog-control-document"</string>

View File

@@ -12,7 +12,10 @@
#include <MiscTools.h>
#include "PixelToImageWriter.h"
#include "PixelToPdfWriter.h"
#include <Common.h>
#include <DefsInsaneWidget.h>
#include <DefsStampWidget.h>
#include <XStampWidget.h>
#include <StampWorker.h>
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<StampDescriptor*> * descriptors)
{
m_stampDescriptors = descriptors;
}
std::pair<int, int> GetStartAndIncrement(InsaneWorker * insaneWorker)
{
wxASSERT_MSG(insaneWorker != nullptr, "insaneWorker is NULL.");
@@ -166,7 +182,8 @@ public:
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<TimeredStatusBar> m_sb = nullptr;
std::unique_ptr<PixelToPdfWriter> m_pixelToPdfWriter;
PixelFilesMap m_pixelFiles;
vector<StampDescriptor*> * 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 );
@@ -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<wxDialog>
(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<XStampWidgets> ( 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<int, wxString> 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<int, int> startAndIncrement = m_scanProject->GetStartAndIncrement(m_insaneWorker.get());

View File

@@ -16,18 +16,23 @@
#include <InsaneWidget.h>
#include <InsaneWorker.h>
#include <XScannerWidget.h>
#include <XStampWidget.h>
#include <XStampWidgets.h>
#include <TimeredStatusBar.h>
#include <ConfigEditorPopup.h>
#include <memory>
#include <vector>
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<uint, std::tuple<std::string, InsaneWorkerEvent::ImageAttributes>> 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<uint, std::tuple<std::string, InsaneWorkerEvent::ImageAttribute
* Button:
* - Right click: shows the scanner widget.
* - Left click: starts scanning.
* - Ctrl + Right click: show the stamp widgets dialog.
*/
class XInsaneWidget : public InsaneWidget
{
DECLARE_DYNAMIC_CLASS( XInsaneWidget )
public:
virtual ~XInsaneWidget();
XInsaneWidget( wxWindow* parent, TimeredStatusBar * sb, wxConfig * config, wxWindowID id = SYMBOL_INSANEWIDGET_IDNAME, const wxPoint& pos = SYMBOL_INSANEWIDGET_POSITION, const wxSize& size = SYMBOL_INSANEWIDGET_SIZE, long style = SYMBOL_INSANEWIDGET_STYLE );
@@ -58,14 +65,19 @@ public:
void ResetScanProject();
void CancelScanning(); // Not tested, probably doesn't work as intended.
void EnableScanButton(bool enable); // For CallAfter.
void Setup();
private:
wxConfig * m_config;
wxWeakRef<TimeredStatusBar> m_sb;
std::vector<StampDescriptor*> * m_stampDescriptors;
// Contains a popup to define the number of pages and double-sided scanning.
std::unique_ptr<ConfigEditorPopup> m_pageStack;
// Contains the scanner widget.
std::unique_ptr<wxPopupTransientWindow> m_ptwScannerWidget;
// Contains the stamp widgets.
std::unique_ptr<wxDialog> m_dlgStampWidgets;
std::unique_ptr<XStampWidgets> m_stampWidgets;
// Available devices and minimal options.
std::unique_ptr<XScannerWidget> m_scannerWidget;
std::unique_ptr<InsaneWorker> m_insaneWorker;

View File

@@ -9,13 +9,15 @@
#include "XScannerWidget.h"
#include "XClientData.hpp"
#include "Common.h"
#include "DefsInsaneWidget.h"
#include <libinsane/constants.h>
#include <fstream>
#include <vector>
using namespace std;
IMPLEMENT_CLASS( XScannerWidget, ScannerWidget )
XScannerWidget::~XScannerWidget()
{}

View File

@@ -16,7 +16,6 @@
#include <ScannerWidget.h>
#include "TimeredStatusBar.h"
#include "InsaneWorker.h"
#include "Common.h"
#include <map>
class BackgroundScannerDiscoveryEvent;
@@ -33,6 +32,7 @@ class BackgroundScannerDiscoveryEvent;
class XScannerWidget : public ScannerWidget
{
DECLARE_DYNAMIC_CLASS( XScannerWidget )
friend class BackgroundScannerDiscovery;
public:
XScannerWidget() {};

View File

@@ -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 <set@nmset.info>\n"
"Language-Team: French <kde-francophone@kde.org>\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. "

View File

@@ -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/'

View File

@@ -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})

View File

@@ -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 <wx/wx.h>
// ----------------------------------------------------------------------------
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

View File

@@ -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 <math.h> // 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);
}

View File

@@ -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 <wx/wx.h>
#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

View File

@@ -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
}

View File

@@ -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 <wx/panel.h>
#include <wx/slider.h>
/*!
* 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_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
#include "wx/msw/wx.rc"

View File

@@ -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
}

View File

@@ -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 <wx/panel.h>
#include <wx/button.h>
/*!
* 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_

View File

@@ -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 <wx/bmpbndl.h>
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<StampDescriptor> ();
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();
}

View File

@@ -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 <wx/wx.h>
#include <wx/config.h>
#include <wx/generic/statbmpg.h>
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<StampDescriptor> 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

View File

@@ -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 <XStampWidget.h>
#include <DefsStampWidget.h>
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<StampDescriptor*> * XStampWidgets::GetStampDescriptors()
{
m_stampDescriptors.clear(); // Stored as unique_ptr in XStampWidget.
for (uint i = 0; i < nbStampWidgets->GetPageCount(); i++)
{
XStampWidget * stampWidget = static_cast<XStampWidget*> (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<XStampWidget*> (nbStampWidgets->GetPage(selectedPage));
if (!stampWidget)
{
evt.Skip();
return;
}
nbStampWidgets->SetPageText(selectedPage, stampWidget->cmbStampLocation->GetStringSelection());
evt.Skip();
}

View File

@@ -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 <wx/wx.h>
#include <wx/config.h>
#include <vector>
#include <memory>
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<StampDescriptor*> * GetStampDescriptors();
private:
wxConfig * m_config;
std::vector<StampDescriptor*> m_stampDescriptors;
void AddStampWidget(wxMouseEvent& evt);
void DeleteStampWidget(wxMouseEvent& evt);
void OnStampLocationChanged(wxCommandEvent& evt);
};
#endif // XSTAMPWIDGETS_H

View File

@@ -419,7 +419,7 @@
<bool name="proxy-wxRIGHT">1</bool>
<bool name="proxy-wxSHAPED">0</bool>
<bool name="proxy-wxTOP">1</bool>
<string name="title">"wxBoxSizer V"</string>
<string name="title">"wxBoxSizer V: szMain"</string>
<long name="title-mode">0</long>
<string name="type">"dialog-control-document"</string>
<document>
@@ -526,7 +526,7 @@ Double-click to go to the selected directory."</string>
<long name="proxy-Height">-1</long>
<string name="proxy-Help text">"Basename"</string>
<bool name="proxy-Hidden">0</bool>
<string name="proxy-Id name">"ID_TEXTCTRL"</string>
<string name="proxy-Id name">"ID_TEXTCTRL_S7"</string>
<long name="proxy-Id value">10003</long>
<string name="proxy-Implementation filename">""</string>
<string name="proxy-Initial value">""</string>
@@ -576,7 +576,7 @@ Double-click to go to the selected directory."</string>
<bool name="proxy-wxWANTS_CHARS">0</bool>
<long name="proxy-X">-1</long>
<long name="proxy-Y">-1</long>
<string name="title">"wxTextCtrl: ID_TEXTCTRL"</string>
<string name="title">"wxTextCtrl: ID_TEXTCTRL_S7"</string>
<long name="title-mode">0</long>
<string name="type">"dialog-control-document"</string>
</document>

View File

@@ -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."));

View File

@@ -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

View File

@@ -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 );

1
XS7.h
View File

@@ -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 );

View File

@@ -11,7 +11,7 @@
#define GLOBALS_H
#define _APPNAME_ "S7"
#define _APPVERSION_ 1
#define _APPVERSION_ 2
#define _INSANEWIDGET_NAME "InsaneWidget"
#endif /* GLOBALS_H */