Commit Graph

4788 Commits

Author SHA1 Message Date
ispyisail 5d2eddfdd1 Merge pull request #1358 from bhangart/fix/bordertitleblock-uninit-members
Initialise the BorderTitleBlock members its constructor compares
2026-10-07 21:18:30 +13:00
ispyisail d508e0adb2 Merge pull request #1359 from bhangart/fix/conductorprofile-uninit-orientation
Initialise the orientations of a default-constructed ConductorProfile
2026-10-07 21:14:36 +13:00
ispyisail a55c1312de Merge pull request #1357 from ispyisail/fix/aligned-text-lines-auto-width
Fix line alignment of multi-line symbol texts with Auto width (#1348)
2026-10-07 21:12:20 +13:00
ispyisail b1f1f77a53 Merge pull request #1365 from ispyisail/feature/customise-dialog
Add a Customise window for toolbars, shortcuts and gestures
2026-10-07 20:57:15 +13:00
ispyisail bae96b4ae7 Merge pull request #1364 from ispyisail/feature/customise-gesture-list
Add a mouse gesture page: own commands, 4 or 8 directions
2026-10-07 20:56:50 +13:00
ispyisail a43ce3baa5 Merge pull request #1362 from ispyisail/feature/folio-paper-size
Add paper sizes A0–A5 to the folio dimensions
2026-10-07 20:54:31 +13:00
ispyisail 0fef6b19ce Add a Customise window: toolbars, shortcut bar, keyboard, gestures
Configuration > Personnaliser... (also at the bottom of a toolbar's
right-click menu) opens one window with a tab for each page that sets
how the user works: Barres d'outils, Contenu des barres, Barre de
raccourcis, Raccourcis and Gestes de la souris, like SolidWorks'
Tools > Customize. The tabs are the same pages the configuration
dialog shows, which keeps them. OK applies every tab, Cancel none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:31:42 +13:00
ispyisail b6bbcfdd7a Merge branch 'feature/customise-gesture-list' into feature/customise-dialog
# Conflicts:
#	tests/qttest/CMakeLists.txt
2026-10-07 18:41:40 +13:00
ispyisail 46e041fe01 Mouse gestures: own command list, 4 or 8 directions
The right-drag ring showed the shortcut bar's commands for the selection.
A new Preferences page, "Gestes de la souris", lets the user pick the
ring's commands per selection context, one per direction, and choose 4 or
8 directions. Commands are dropped from the list onto a slot of a ring
editor, or placed with a button; Delete empties a slot.

A context the user never edits keeps following the shortcut bar, and 8
directions stays the default, so nothing changes for anyone who does not
open the page. A picked list is positional: a direction left empty, or
holding a command this build lacks, stays empty instead of shifting the
others. Stored like ShortcutBarSettings: diagrameditor/gestures/<context>
id lists in QSettings, defaults not stored.

tst_gesturesettings covers the defaults, positional lists, the 4/8
setting, the overlay's sectors and empty slots, and the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 18:38:25 +13:00
ispyisail 3a61513f29 Let the user choose what each folio editor toolbar holds
Configure QElectroTech > Toolbar contents: pick a toolbar, drag or add
commands from the list on the left, remove them with Delete, reorder,
add separators, and add, rename or delete toolbars of one's own.
Reset to defaults gives a toolbar its original contents back.

Each toolbar is stored as a list of command ids in QSettings
(diagrameditor/toolbars/<objectName>), the same pattern the shortcut
bar uses. A toolbar the user never changed stores nothing and is built
exactly as before; an id no command carries any more is skipped. The
four buttons that are widgets rather than commands (handle size, text
grid, background colour, conductor colour) get ids of their own and
can each be on one toolbar at a time. Stored scripts can go on any
toolbar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 18:34:51 +13:00
ispyisail 5f21d4fce2 Paper size presets: never fit fewer than 3 columns or rows
fitCells() tried counts from 1, but BorderTitleBlock raises any column
or row count below 3 to 3. With very large cells (A5 portrait with
columns of about 200 px or more) the preset picked 2 columns; the folio
then got 3, came out wider than the sheet, and the dropdown fell back
to "Custom". Start the search, and the capped fallback, at 3, and
refuse a paper that leaves no room for 3 cells of the smallest size.

A5 portrait with 300 px columns now gives 3 x 179 px instead of
2 x 269 px; A4 landscape with the default cells is unchanged
(19 x 58 px). ctest 65/65.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 18:07:03 +13:00
Laurent Trinques 437729df15 Merge pull request #1327 from ispyisail/feature/customise-toolbar-options
Add a Toolbars settings page: icon size, text with icons, lock
2026-10-07 06:50:11 +02:00
Laurent Trinques 0b993f4d89 Merge pull request #1344 from bhangart/fix/headless-log-to-stderr
Write the messages of a headless run to stderr on Windows too
2026-10-07 06:47:33 +02:00
Laurent Trinques 5106dd3029 Merge pull request #1360 from bhangart/fix/elementpicturefactory-text-leak
Delete the text items ElementPictureFactory::build() creates and drops
2026-10-07 06:45:38 +02:00
Laurent Trinques e107c9444f Merge pull request #1356 from ispyisail/fix/composite-text-variable-insert
Fix composite text dialog not inserting variables (#1348)
2026-10-07 06:42:54 +02:00
Laurent Trinques 223ace3a40 Merge pull request #1347 from saschbe/fix/background-color-menu-title
fix: name the sheet background color submenu
2026-10-07 06:39:00 +02:00
Laurent Trinques 5c38907204 Merge pull request #1346 from ispyisail/fix/1336-edit-menu-submenus
Fix #1336: split the long Edit menu into submenus
2026-10-07 06:38:22 +02:00
Laurent Trinques 211075f1b3 Merge pull request #1343 from bhangart/feature/element-editor-text-field-handles
Resize text fields in the element editor by dragging a corner
2026-10-07 06:36:48 +02:00
ispyisail 2752e6705c Folio properties: paper size presets A0-A5, landscape or portrait
A "Format" choice in the folio dimensions box sets the columns and rows
so the whole folio, title block included, has the size of an ISO A
sheet at the 96 dpi the PDF export uses. A4 landscape keeps 60 px
columns and 80 px rows and comes out as an A4 page in the PDF.

Nothing new is stored: the choice only fills in the columns and rows.
A folio whose size already matches a paper shows that paper; any other
shows "Custom". Changing the title block template after picking a paper
fits the folio again; a template too tall for the paper falls back to
"Custom".

The same box is in Folio properties and in the new-folio defaults of
the project and application settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 17:36:22 +13:00
Laurent Trinques e2fd2d1c20 Merge pull request #1342 from bhangart/feature/free-text-resize-handles
Resize free texts by dragging a corner
2026-10-07 06:36:06 +02:00
Laurent Trinques 96fc0b9d4a Merge pull request #1341 from bhangart/feature/free-text-width-spinbox
Set the width of free texts in their properties
2026-10-07 06:35:17 +02:00
Laurent Trinques 60237d7070 Merge pull request #1353 from ispyisail/feat/dxf-block-data
Add symbol part data to DXF blocks as hidden attributes (#1339)
2026-10-07 06:34:16 +02:00
Laurent Trinques 9396a367db Merge pull request #1352 from ispyisail/feat/dxf-block-labels
Add an option to export symbol texts as DXF block attributes (#1339)
2026-10-07 06:33:37 +02:00
Laurent Trinques 7e9b479a57 Merge pull request #1351 from ispyisail/feat/dxf-symbol-blocks
Add an option to export symbols as DXF blocks (#1339)
2026-10-07 06:32:51 +02:00
Laurent Trinques 3d5100789b Merge pull request #1350 from ispyisail/fix/1339-dxf
Fix DXF export of circles, arcs and right-side title blocks (#1339)
2026-10-07 06:31:57 +02:00
ispyisail 36df4b3010 Centre or right-align the lines of symbol texts with an automatic width (#1348)
A symbol text on a folio with its width on "Auto" kept every line of a
multi-line text on the left, whatever its alignment: a QTextDocument
with no text width has no width to centre or right-align lines in. It
only worked once the user gave the text a width wide enough.

With the width on Auto and a centre or right alignment, give the
document the width of its longest line. The size of the text does not
change, only where the shorter lines sit. The fit is redone when the
text, the alignment, the width or the font changes; on a font change
the text's anchor is kept, as the font change itself does.

textWidth() now returns the width the user set (-1 for Auto), the value
that is saved, rather than the document's, as IndependentTextItem
already does. Readers (properties panel, resize-handle undo, script
API, project database) see -1 for Auto as before.

Checked: every folio of the 25 example projects renders identically to
master (136 PNGs); a centred and a right-aligned two-line text now
render aligned; changing their font size leaves the same box and anchor
as master, and without the font-change refit the lines wrap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 13:12:22 +13:00
Beat Hangartner e50e6a492e Put stdout of a headless run into binary mode on Windows too
stderr got it in the previous commit; stdout (the JSON of --info, the
messages of the exports) still ended its lines in "\r\n" on Windows
while stderr ended them in "\n". Both streams now give the same bytes
on every system.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 01:51:00 +02:00
Beat Hangartner 9882a79a93 Refresh the free text handles when the text comes back to a folio
itemChange() removed the corner handles when the text left the scene
but did not bring them back when it returned still selected, which Qt
allows (undoing a scripted delete does it) without a selection change.
Refresh on every scene change. The two handle helpers are protected:
nothing outside the class calls them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 01:51:00 +02:00
Beat Hangartner 2c9900eca8 Make 0 the automatic width in the free text width box
The box showed Auto for -1 while IndependentTextItem::setTextWidth()
treats every value up to 0 as automatic. Typing 0, or the first click
on the up arrow from Auto, then put a width change in the undo history
that changed nothing, left the box on 0, and in live edit every later
change of X, Y, angle, text or size was replaced by that empty command.
Auto is 0 in the box now, like in the setter: no number is the automatic
width, and the first step up is 1 px.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 01:51:00 +02:00
Beat Hangartner 2e4982e871 Drop a check that cannot trigger in the element editor
A dynamic text field is never edited inline in the element editor (it
never sets text interaction flags), so the handles never had to hide
for it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 01:50:05 +02:00
ispyisail b9d459b0e6 Fix composite text dialog not inserting variables under Qt 6 (#1348)
The slot was auto-connected by name to QComboBox::activated(QString),
which Qt 6 removed, so connectSlotsByName() found no signal and picking
a variable in the "Texte composé" dialog did nothing. activated(int)
exists in Qt 5 and Qt 6; the slot never used its argument and reads
currentData() as before.

Same fix as the CompositeTextEditDialog half of #674, which was closed
unmerged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 12:49:37 +13:00
ispyisail aa6abe6e81 Export a symbol's part data as hidden attributes of its DXF block (#1339)
With symbols as blocks, every non-empty information field of a symbol
(label, manufacturer, reference, supplier, quantity...) is written as a
hidden attribute of its INSERT, tagged with the field's name. A CAD
program can then list the parts from the drawing, as with AutoCAD's
attribute extraction; hidden, they change nothing on screen, in any
reader. A field already written as a visible attribute (with
--dxf-attributes) is not repeated. The label formula is left out: it is
how the label is made, not part data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:14:13 +13:00
ispyisail 9699b314b0 Add an option to export a symbol's texts as DXF block attributes (#1339)
With symbols as blocks and the new "DXF : textes des symboles en
attributs" option (--dxf-attributes on the command line), a symbol's own
texts (its label, function, comment...) are attributes of its INSERT
instead of loose texts, so a CAD program moves them with the symbol and
can list or edit them. Each is written exactly where, and as, the text
was. A text showing an information field is tagged with its name
(LABEL, FUNCTION...), a typed text TEXT1, TEXT2...; a text's second line
gets _2. The block defines each tag once, placed where the first symbol
has it.

Its own option, off by default, because LibreCAD (2.2.1.5) does not
show attributes: the labels would vanish there. AutoCAD shows them.

The text geometry moves into textLines(), shared with the text loop,
so the attributes and the plain texts cannot drift apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:12:20 +13:00
ispyisail c3ed2daca8 Add an option to export symbols as DXF blocks (#1339)
With "DXF : symboles en blocs" ticked in the export dialog, or
--dxf-blocks on the command line, each symbol definition a folio uses is
written once as a DXF block and every placed symbol as an INSERT of it.
A CAD program then selects, counts and replaces a symbol as one object.

The block is drawn by the same code as a symbol drawn in full, as if
the symbol sat unturned at the folio's origin, which is DXF (0,
sheetHeight): that is the block's base point, so the INSERT carries the
symbol's position and quarter-turn and nothing else. Blocks have to come
before any entity, so the export collects them first and dxfBegin()
writes them in its BLOCKS section. Entities in a block keep their own
layers. Off by default; with it off the file is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 09:50:18 +13:00
ispyisail 83f72c95c6 Fix DXF export of circles, arcs and the title block at the right (#1339)
Circles and arcs: drawArcEllipse() split each curve into quarters and
fitted a circular ARC through a point half way between the curve and its
chord, so every circle came out as a flattened diamond. A circle or an
arc of one is now one exact CIRCLE or ARC. R10 has no ELLIPSE entity, so
a true ellipse is a polyline through the curve, one point every 5
degrees. The export also used a different scale on each axis, which made
round things oval; it now uses one, the largest that fits the sheet.

Title block at the right: the DXF laid the horizontal template out in
the narrow vertical strip, squashing it into the top corner. It is now
laid out horizontally and turned a quarter, as draw() turns the painter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 08:13:52 +13:00
saschbe 8ff5fbac0c Preserve imported image colours by default in dark mode 2026-10-06 21:09:41 +02:00
Sasch_be 0421ea1586 fix: name the sheet background color submenu 2026-10-06 20:46:25 +02:00
ispyisail 2867708369 Fix #1336: fold Edit menu families into submenus
The Edit menu had grown to 42 entries and no longer fitted on a laptop
screen; Qt wrapped it into a second column. Select, Group, Rows and
columns and Depth now sit one level down, as Add and Align already did.
Search for a command, Shortcut bar and Repeat move to the end, beside
Search/Replace. No action, label or shortcut changes: Ctrl+A was checked
to still select everything from inside the new Select submenu.

Lignes et colonnes was already built as a submenu for the folio's
context menu; the Edit menu now uses the same one instead of a flat copy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 07:43:45 +13:00
ispyisail 27403acc2c Merge remote-tracking branch 'upstream/master' into feature/customise-toolbar-options
# Conflicts:
#	tests/qttest/CMakeLists.txt
2026-10-07 07:33:20 +13:00
ispyisail bf3c0fc633 Toolbars settings: only update windows that took them
applyToAll() restyled every QMainWindow, including the terminal strip
editor and the print window, which never read the settings when they
open: they changed on OK and went back to defaults when reopened.
applyTo() now marks the window, and applyToAll() only updates marked
windows, so the page covers the folio, element and title block editors
as described.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 07:05:12 +13:00
Beat Hangartner ad14eb1724 Delete the text items ElementPictureFactory::build() creates and drops
parseText() creates a QGraphicsSimpleTextItem for every <text> of an
element (the DXF export reads them later) and appends it to the
primitives it is given. build() draws every primitive twice, once for
the normal and once for the low-zoom picture, and gave the second pass
a fresh `primitives fake_prim` per primitive that went out of scope
with its text items still allocated. dropCache() also removed a
location's primitives without deleting their text items.

LeakSanitizer on the Linux CI sanitizer build (separate PR) stops
every --resave or export of a project whose elements have texts:

  ERROR: LeakSanitizer: detected memory leaks
  Indirect leak of 37200 byte(s) in 75 object(s) allocated from:
    #1 QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(QGraphicsItem*)
    #2 ElementPictureFactory::parseText(...) elementpicturefactory.cpp:658
    #4 ElementPictureFactory::build(...) elementpicturefactory.cpp:324

Give the low-zoom pass one set of primitives for the whole element and
delete its text items when both pictures are drawn; in dropCache(),
take the primitives out of the hash and delete their text items. The
items kept in m_primitives_H for the DXF export are unchanged, and the
destructor deletes those as before.

No file-format change, nothing drawn differently. Tests: the
sanitizer job on Linux fails on master with the report above and
passes with this change; ctest on macOS 64/64. The leak is invisible
to a plain test and to ASan on macOS, which has no LeakSanitizer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Beat Hangartner <beat@hangartners.ch>
2026-10-06 17:42:19 +02:00
Beat Hangartner e1acf95da4 Initialise the orientations of a default-constructed ConductorProfile
ConductorProfile's default constructor leaves beginOrientation and
endOrientation untouched, and the copy constructor and operator= then
read them from such a profile when a conductor's profiles are stored in
a QHash. UndefinedBehaviorSanitizer stops the binary there on every
project with conductors:

  conductorprofile.cpp:42:23: runtime error: load of value 1869263360,
  which is not a valid value for type 'Qet::Orientation'
    #0 ConductorProfile::ConductorProfile(ConductorProfile const&)
    #2 QHashPrivate::Node<Qt::Corner, ConductorProfile>::createInPlace

Give both members a default value, Qet::North, in the header. No
behaviour changes: a default-constructed profile is null (no segments)
and its orientations are never used before fromConductor() sets them.

No file-format change. Tests: the sanitizer build of the Linux CI job
(separate PR) fails on master with the report above and passes with
this change; all 23 example projects go through --export-svg and
--resave under ASan/UBSan on macOS without a report.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Beat Hangartner <beat@hangartners.ch>
2026-10-06 17:26:46 +02:00
Beat Hangartner a9354d67ba Initialise the BorderTitleBlock members its constructor compares
The constructor of BorderTitleBlock sets the border and title block
properties through importBorder() and importTitleBlock(). Their setters
(displayColumns(), setColumnsCount(), ...) compare the new value with
the member before storing it, and at that point the members have never
been written: display_columns_, display_rows_, the counts and sizes,
and m_edge are read uninitialised. UndefinedBehaviorSanitizer stops
every command-line run of the binary on the first of them:

  bordertitleblock.cpp:455:23: runtime error: load of value 190,
  which is not a valid value for type 'bool'
    #0 BorderTitleBlock::displayColumns(bool)
    #1 BorderTitleBlock::importBorder(BorderProperties const&)
    #2 BorderTitleBlock::BorderTitleBlock(QObject*)

Give those members a default value in the header: false, 0 and
Qt::BottomEdge. The constructor then compares against known values. No
behaviour changes: the only effect of the comparisons in the constructor
is a displayChanged() signal nobody is connected to yet, and the
defaults of BorderProperties and TitleBlockProperties are all non-zero,
so no setter skips its clamp.

No file-format change. Tests: the sanitizer build of the Linux CI job
(separate PR) fails on master with the report above and passes with
this change; ctest on macOS 56/57, the failure being tst_elementautonumids
as on master.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Beat Hangartner <beat@hangartners.ch>
2026-10-06 17:25:59 +02:00
Beat Hangartner 4e090e6ec2 Write the messages of a headless run to stderr on Windows too
The exports, --info, --resave and --run return before QetLogger's
handler is installed, so they keep Qt's default handler. On Linux and
macOS it writes to stderr. On Windows it writes to the debugger when the
program has no console, and a GUI program started by another program
never has one: everything a headless run reported -- a wire that could
not be reconnected, which way the project database was filled, an
element that could not be read -- was lost to the caller, a test or a
tool like qet-mcp. Install a handler for these runs that writes to
stderr in the form the default handler uses on the other systems (the
default message pattern, UTF-8).

On macOS the stderr of --info, --resave, --run and --export-svg is
byte-identical before and after (memory addresses aside). On Windows,
tst_databasefromdocument and tst_terminaluuids, which read these
messages, fail before and pass after.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 17:17:12 +02:00
Beat Hangartner 3c67147824 Resize text fields in the element editor by dragging a corner
In the element editor, a dynamic text field that is the only selected
item gets the corner handles of TextResizeHandles: dragging one sets
the width the field wraps to, keeping the opposite corner in place;
double-clicking a handle goes back to the automatic width. One undo
step per drag, on the editor's undo stack.

ElementScene keeps the handles of the same text when the undo stack
changes: pushing the resize itself calls managePrimitivesGroups()
again, and deleting the handles there would delete them while they are
still emitting.

No file format change (text_width on <dynamic_text> already exists).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 17:17:12 +02:00
Beat Hangartner 2989f6cb4b Resize free texts by dragging a corner
A selected free text gets the corner handles of the previous commit:
dragging one sets the width the text wraps to, keeping the opposite
corner in place; double-clicking a handle goes back to the automatic
width. One undo step per drag, on the folio's undo stack. The handles
are hidden while the text is typed in.

DiagramTextItem shows the handles for a subclass that asks for them
(textResizeHandlesWanted()); only free texts do for now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 17:17:11 +02:00
Beat Hangartner b07378bf6e Set the width of free texts in their properties
A "Width" spin box in the properties of a free text sets the width it
wraps to (previous commit). "Auto" (-1) is the automatic width. It also
works with several selected texts, like the size and the angle; texts
with different widths show "Auto" and are left alone unless the box is
changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 17:17:11 +02:00
Laurent Trinques a498e91b53 Merge pull request #1334 from ispyisail/fix/msvc-qprinter-copy
Fix the Windows MSVC build broken by live mode printing (#1333)
2026-10-06 16:36:58 +02:00
Laurent Trinques 4af441f895 Merge pull request #1326 from ispyisail/feature/customise-shortcuts-page
Add icons, menu locations, key search and copy to the Shortcuts page
2026-10-06 16:29:26 +02:00
Laurent Trinques 1dfb70870f Merge pull request #1325 from ispyisail/feature/customise-command-ids
Add the missing folio editor commands to the Shortcuts page
2026-10-06 16:27:36 +02:00