Commit Graph

728 Commits

Author SHA1 Message Date
Kellermorph 4edd4932bb Fix PLC table dangling reference warning and row deletion 2026-08-22 16:42:13 +02:00
Kellermorph f6afd87522 Fix dock widget size/position not being restored on Qt6 2026-08-22 11:08:02 +02:00
plc-user 5db77fe40c Merge pull request #747 from ispyisail/fix/parttext-real-font-size-desync
Fix real_font_size_ desyncing from the actual font in PartText
2026-08-22 10:27:14 +02:00
Levi Jetzer 31feb7b7b0 Show the element editor's Informations tab for Terminal and Thumbnail
setTabVisible(1, ...) only allowed Simple and Master, but the tree
(updateTree()) and the actual write path (ElementScene::toXml()) both
already support elementInformations for Terminal and Thumbnail too --
three independent "is this type allowed" checks that were never
reconciled, leaving already-working support unreachable through the
UI for those two types. Slave stays excluded here, consistent with
having no elementInformations support at either of the other two
points either (separate, larger gap, not addressed here).
2026-08-21 16:23:41 +02:00
Levi Jetzer 622791f994 Remove auto_num_locked/potential_isolating/exclude_from_bom checkboxes'
"false" writes, delete key instead

Unchecking a checkbox previously wrote the key with value "false"
rather than omitting it -- behaviorally identical to every consumer
(all three do a case-sensitive == "true" comparison), but left dead
entries cluttering the .elmt file, inconsistent with how other
elementInformation fields (manufacturer, designation) are only present
when actually set. Now removes the key entirely when unchecked.
2026-08-21 15:59:06 +02:00
Levi Jetzer 7c941e4697 Guard numeric elementInformation fields against "." and normalize decimal comma
- ElementInfoWidget::currentInfo() now skips a field whose validator
  hasn't accepted its text (e.g. a lone "." mid-typing), which
  previously stored and later parsed to 0.
- New QETInformation::NumericInfoValidator rewrites "," to "." before
  validating, so 80,5 on a German/French keyboard no longer silently
  becomes 805. Used at both existing call sites.
- Restored the header's #1/#2/#3 doc comment (was reflowed into a
  run-on paragraph by a previous edit).
2026-08-21 15:16:36 +02:00
Levi Jetzer 884ec4bbb9 Add editable "auto_num_locked"/"potential_isolating"/"exclude_from_bom"
checkboxes to the element editor

These elementInformation keys were previously only editable on an
already-placed instance (via ElementInfoWidget on the diagram side).
Since elementInformation values are seeded from the .elmt file's own
<elementInformations> block at placement time, a symbol author had no
proper way to set these as the *default* for every future placement --
only a workaround via the generic, unvalidated key/value tree.

Adds dedicated checkboxes to ElementPropertiesEditorWidget, mirroring
ElementInfoWidget's own labels/behavior: auto_num_locked and
potential_isolating inside the existing terminal-only group
(m_terminal_gb, shown only for ElementData::Terminal), exclude_from_bom
always visible regardless of type. Written after the generic tree loop
so they take precedence over any stale raw entry for the same key.
No new storage or file format change -- purely a missing editor UI for
an already-existing mechanism.
2026-08-19 17:58:16 +02:00
ChuckNr11 9d81a9788f move position of element editor coord display to center of statusbar
for better visibility only
2026-08-19 12:00:43 +02:00
ChuckNr11 2803dcf8b8 Change live cursor-coordinate readout on running ESEvent
During an ESEvent, the mouse position was used without format with
`snapToGrid` to display the coordinates. However, since the `helpCross`
is positioned using `snapToGrid` during these events, the displayed
coordinates did not match the `helpCross` position.
The command for sending the coordinates has been moved to the
`ESEventInterface` to function 'updateHelpCross' and now transmits the
position of the intersection point of the helpCross lines.
2026-08-18 14:19:33 +02:00
Levi Jetzer fb0649ceee Fixed incorrect OR and AND checks 2026-08-14 22:23:25 +02:00
Kellermorph fe6191f26d Fix slave contact groups being trimmed to one when reopening element properties 2026-08-14 10:31:15 +02:00
ispyisail 3077527601 Fix real_font_size_ desyncing from the actual font in PartText
Follow-up to #158 / PR #501. While investigating that position bug,
found a second, separate one in the same area: PartText::setFont()
never updated real_font_size_, so it stayed frozen at whatever size the
item was constructed with.

That field isn't cosmetic - it's live data two other operations depend
on:

- startUserTransformation()/handleUserTransformation() use it as the
  base size when scaling the font as the user drags a resize handle.
  With it stale, dragging a handle after changing the size via the
  toolbar (or loading a file with a non-default size) scales from the
  wrong starting point - the resulting size has nothing to do with
  what's visibly on screen.
- flip() reads it directly to compute the repositioning offset, so a
  stale value also mis-positions the item on flip.

Fix: update real_font_size_ inside setFont(), the same place PR #501
already re-runs adjustItemPosition() for the same reason (font changed,
keep everything that depends on it in sync). fromXml() already routes
both its "size" and "font" attribute branches through setFont(), so
loaded elements pick this up for free.

Verified with a temporary instrumented build: typed a size into the
element editor's font-size field three times (9 -> 4 -> 48). Each
setFont() call's "before" value exactly matched the previous call's
"after" value, confirming real_font_size_ now tracks every change
instead of freezing at its construction-time value (9). Instrumentation
removed before committing.
2026-08-14 20:21:16 +12:00
Andre Rummler 6d05bc2f21 Remove all Qt version checks and branches for <5.15.12 as such versions are no longer supported. 2026-08-13 16:20:30 +02:00
Andre Rummler 7ba295a339 Remove all Qt version checks and branches for <5.14.0 as such versions are no longer supported. 2026-08-13 15:45:15 +02:00
Laurent Trinques 2186d2733f Merge pull request #709 from arummler/master-continue-qt6-migration
Qt6 migration beyond signal/slot
2026-08-13 10:55:47 +02:00
ispyisail 6f9f5f84c2 Fix bugtracker #243: allow copying out of a read-only element
Opening an element you cannot write -- anything from the QET collection,
for instance -- disabled Copy along with everything else, so there was no
way to reuse a primitive from it. The workaround was to save the whole
element into your own collection first, just to take one shape out of it.

Two actions stood in the way, and neither of them modifies anything:

- Select All and Invert Selection were in the list disabled outright when
  read only, so nothing could be selected in the first place;
- Copy was enabled only when "!m_read_only && selectedItems().count()", so
  even a mouse selection left it greyed out.

Both now work on a read-only element. Copy is safe there:
ElementScene::copy() serialises the current selection to the clipboard and
touches neither the element nor the file.

Cut, Paste, Paste-in-area, Delete, Rotate, Flip, Mirror, the depth actions
and the add-primitive tools stay disabled exactly as before, so the element
is still protected -- this only stops the editor from refusing to read out
what it is already displaying.

Verified with a chmod 444 element: Select All then Copy now work, the
clipboard receives the expected <definition> with all three primitives,
Cut/Paste/Delete remain greyed out, Save stays disabled, and the file is
untouched (same permissions, same checksum).
2026-08-13 11:28:51 +12:00
Andre Rummler c14d6a6dd6 In order to migrate to Qt6 all options for KF6 were added:
a) using a system provided KF6
b) downloading and compiling KF6
c) using the vendored-in re-creation of the functionality

The behaviour for both Qt5 and Qt6 is steered with the same two variables which were renamed to become version agnostic:
a) BUILD_WITH_KF=ON BUILD_KF=OFF
b) BUILD_WITH_KF=ON BUILD_KF=ON
c) BUILD_WITH_KF=OFF

The version is automatically derived from the chosen Qt major version.
2026-08-12 12:29:56 +02:00
Levi Jetzer 5dbb9f28de Fix numeric field validation gaps found in review
Address feedback on the width/height/depth elementInformation fields:

- The regex accepted "." alone as a complete value ([0-9]* permits
  zero digits on both sides), meaning a field could be committed with
  a literal "." saved to the XML. Require at least one digit either
  before or after the separator.
- The same pattern was duplicated verbatim in elementinfopartwidget.cpp
  and elementpropertieseditorwidget.cpp's EditorDelegate. Factored into
  QETInformation::numericInfoPattern(), a single shared definition both
  call sites now use.
- Tightened the pattern to at most 2 decimal places (down from 4) to
  match the precision actually meaningful for these fields.

Not changed, by design:
- Storage stays a plain string, consistent with every other numeric
  elementInformation field (quantity etc.) in this codebase -- values
  round-trip through XML text regardless, so a long/micron
  representation wouldn't avoid the string<->number conversion, only
  relocate it.
- No decimal-comma normalization needed: with the fixed pattern, only
  digits and "." are ever accepted at the keystroke level, so an
  alternate separator can't enter the field in the first place.
2026-08-12 08:43:42 +02:00
ispyisail 762bd7febf Fix bugtracker #333: selecting several dynamic texts overwrites their colours
Selecting more than one dynamic text field in the element editor silently
replaced every selected field's colour with the colour of the first one.
Nothing was clicked -- merely extending the selection destroyed the others'
colours, and the change went onto the undo stack as if the user had asked
for it.

Cause: updateForm() loads the current part's colour into the colour button
with m_color_kpb->setColor(). KColorButton::changed is emitted for a
programmatic setColor() just as it is for user interaction, and it is
connected to m_color_kpb_changed(), which applies the new colour to *every*
part in m_parts. So simply displaying the first part's colour wrote that
colour to all the others.

Every other widget in updateForm() is immune because it is wired to a
user-only signal -- on_m_x_sb_editingFinished(), on_m_frame_cb_clicked() --
which setValue() and setChecked() do not emit. The colour button is the one
control whose signal cannot distinguish the two, so block it while loading.

This also explains why the reporter saw it only when rubber-band selecting
bottom-to-top: the write happens only when the first part's colour differs
from what the button already shows, which depends on selection order.

Verified in the element editor with two dynamic texts, one red and one blue:
select the red one, then ctrl-click the blue one. Before: the blue text
turned red. After: both keep their colours. Changing the colour deliberately
with the button still applies to all selected texts, as intended.
2026-08-12 15:53:30 +12:00
Levi Jetzer 7347322221 Replace QDoubleValidator with QRegularExpressionValidator on width/height/depth fields
The selection properties dock (elementinfopartwidget.cpp) and the
element editor's information tree (elementpropertieseditorwidget.cpp's
EditorDelegate) both restrict the width/height/depth fields added for
cabinet layout support to numeric input via a validator.

QDoubleValidator follows the system/UI locale for its decimal
separator, which meant a comma was accepted as an intermediate state
and left the field impossible to leave in some contexts, even though
it was never a valid final value.

Switch both to a QRegularExpressionValidator matching
^[0-9]*\.?[0-9]{0,4}$: "." is a literal character in the pattern, not
locale-dependent, and [0-9] (rather than \d) excludes non-ASCII
digits. This guarantees a value entered this way can always be read
back with QString::toDouble() without locale handling. The check for
which keys are numeric (QETInformation::isNumericInfoKey) is shared
between both call sites; the validator setup itself stays local to
each, since QETInformation intentionally has no Qt Widgets dependency.

Also adds a placeholder ("ex. 80.5") and tooltip explaining the
expected format.
2026-08-11 18:01:10 +02:00
Levi Jetzer c23999acd1 Added width/height/depth properties to element definitions
Adds three new elementInformation keys — width, height, depth (in mm)
— alongside the existing manufacturer/manufacturer_reference fields.
These describe the physical dimensions of the device a symbol
represents, set once per element definition.

Values are restricted to plain decimal numbers via a QDoubleValidator
on the information tree's item delegate (fixed-point, "." as decimal
separator via QLocale::c(), independent of the UI language), so a
later consumer can always parse them with toDouble() without
additional sanitization.
2026-08-11 16:09:34 +02:00
ispyisail 7afc1eb56b Enable Information tab in element editor for Slave and Terminal basetypes
GitHub issue #663: the "Informations" tab in the element editor's
properties dialog was only made visible for Simple and Master basetypes
(setTabVisible gate in on_m_base_type_cb_currentIndexChanged), hiding it
entirely for Slave and Terminal Block elements.

This wasn't a data-model limitation: ElementData::m_informations is read
and written identically for every basetype (elementdata.cpp), and
updateTree() already special-cased Terminal as enabled and injected
PLC-specific info rows for PLC Slave elements - that logic was simply
unreachable because the tab itself was hidden for both types. Also
flipped updateTree()'s Slave case from setDisabled to setEnabled so the
tree is actually editable once visible, matching Terminal's existing
behavior.

This lets users attach manufacturer/part-number/reference metadata
directly to Terminal Block and Slave (e.g. multi-part contactor)
elements, as requested in the issue - useful when a Slave's part number
differs from its Master's (e.g. a contactor's auxiliary contact block
vs. its coil).

Not verified: interactive element-editor GUI testing wasn't performed
in this sandbox; verified via clean incremental build only.
2026-08-11 18:00:43 +12:00
Laurent Trinques 7f75500023 Merge pull request #694 from IBSYSLevi/feature/center-rotation-option-for-textfields
Feature added: Rotation point center property for dynamic text fields
2026-08-09 21:09:19 +02:00
Laurent Trinques cdf5cad1e5 Merge pull request #698 from arummler/master-modernize-signal-slot
Migrate string based signal/slot to method pointer
2026-08-09 21:08:28 +02:00
Kellermorph 5e02111600 Fix-PLC-Warnings 2026-08-09 18:27:20 +02:00
Andre Rummler c7ed3229d0 Migrating more SLOT() macros. 2026-08-09 12:30:15 +02:00
Andre Rummler 5adf61936b Merge branch 'master' into master-modernize-signal-slot 2026-08-08 23:13:42 +02:00
Andre Rummler 90950075bf Three connects paired a zero-argument signal with a slot that has a default-valued parameter (e.g. void applyEnable(bool = true)).
Default arguments aren't part of a function's pointer-to-member type, so &Class::slot has a type requiring the argument regardless of its
default value -- incompatible with a signal providing none, and &Class::slot alone won't compile against these signals at all.
When migrating to the modern member pointer connect, replaced  with a lambda that calls the slot with no arguments, letting
the default apply exactly as before.

- SelectAutonumW::applyEnable(bool = true), connected to each  NumPartEditorW's changed() signal in both setContext() and
  on_add_button_clicked(). The corresponding disconnect() in on_remove_button_clicked() is removed rather than reimplemented: a
  lambda-based connection can't be matched and removed by a  separately-written disconnect() call, and the explicit disconnect
  was already redundant -- the very next line deletes the part object, which Qt automatically disconnects on destruction (the same
  guarantee setContext()'s own qDeleteAll() cleanup already relies  on).
- PartText::adjustItemPosition(int = 0), connected to QTextDocument::contentsChanged().
- ExportDialog::slot_changeFilesExtension(bool = false), connected to ExportPropertiesWidget::formatChanged().
2026-08-08 21:39:31 +02:00
Andre Rummler a668ccfa90 Migrating the remaining signal/slot connects with an ambigious activated(int) via qOverload<int>,
since QComboBox::activated(QString) still exists pre-Qt6 and makes &QComboBox::activated alone ambiguous:

- StyleEditor: outline_color/line_style/size_weight/filling_color,
  both connect (activeConnections(true)) and disconnect
  (activeConnections(false)) branches. antialiasing's stateChanged(int)
  connect modernized alongside them (single signal, no disambiguation
  needed).
- TitleBlockTemplateCellWidget: cell_type_input_ (two connects to
  different slots), horiz_align_input_, vert_align_input_, logo_input_.

Also modernises QETApp's system tray connect.

In two cases stateChanged already replaced with version guarded checkStateChanged for future proofing.
2026-08-08 21:29:17 +02:00
Levi Jetzer 615e40dee2 Feature added: Rotation point center property for dynamic text fields
Now a new checkbox in the dynamictextfieldeditor is available (by default set to false for legacy) to make it possible to turn dynamic text fields around its own center.
This resolves an undesirable behaviour that occurs when the text alignment is retained

Including translation to english and german
2026-08-08 11:10:36 +02:00
Levi Jetzer d7c75ea5a5 Fixed saving coil master -> correction +
Added space for a better style ;)
2026-08-08 09:07:22 +02:00
Levi Jetzer b9153269a4 Fixed saving coil master -> correction
Added check to the type of master so that types which are not using "max slave elements" are saved with the value -1 (infinity).
2026-08-08 09:05:27 +02:00
Andre Rummler 62ad49a6d3 Update old fashioned SIGNAL/SLOT to point-to-member. Only simple and clear cases. 2026-08-08 00:32:31 +02:00
Levi Jetzer eab9603d8a Fixed saving coil master
Removed "isVisible" check on max_slave_checkbox before saving because isVisible is maybe not true, when the ok button is pressed
Then the value -1 is written and so on not saved to the elements xml
2026-08-07 21:52:40 +02:00
Levi Jetzer 72c8008218 Avoid needless dock churn in QETElementEditor::updateInformations()
updateInformations() runs on every selection change and on every undo
stack index change. It unconditionally called clearToolsDock(), which
removes and hides the current editor widget, and then re-inserted the
same widget into the stack. When the editor for the new selection is
the one already shown, that means removing, hiding, reparenting and
re-adding a widget only to end up in the same state.

Look up the editor first and only clear and re-insert the tools dock
when a different editor is needed. setPart()/setParts() still updates
the contents in every case, so the visible result is unchanged.
2026-08-06 17:20:48 +02:00
Kellermorph 4f9474a05f PLC Fix scroll sync, data persistence, font defaults, copy/paste, and layout fixes 2026-08-06 07:33:39 +02:00
ispyisail eb520ac3f8 Pre-fill SVG export filename with the element's own name
Suggests the element's filename (without its .elmt extension) as the
default save name when exporting to SVG, instead of only defaulting to
the customElementsDir with no filename. Addresses plc-user's review
suggestion on PR #637.
2026-08-03 08:31:17 +12:00
ispyisail 8a72230916 Add "Export to SVG" to the element editor
Implements discussion #605. The diagram editor can already export a folio
to SVG; the element editor, where a single .elmt symbol is drawn, had no
export capability at all -- confirmed by grepping its header for "export"
before starting: nothing.

## Renders the live scene, not ElementPictureFactory's cache

The discussion proposed sourcing this from ElementPictureFactory's cached
per-element QPicture (m_pictures_H), the one used for the elements-panel
preview icons. Checked that cache's actual invalidation before building on
it: nothing in the editor ever tells it to drop an entry on edit, and it is
keyed by the element's on-disk uuid. So for any element already previewed
once in the panel, exporting from the cache would silently produce stale
content after any edit; for a brand-new, never-saved element, no entry
would exist at all. Neither is acceptable for a File > Export action a
user expects to reflect what's on screen right now.

Renders ElementScene directly instead, the same way
ExportDialog::generateSvg() already renders the live Diagram for the
diagram editor's own SVG export: no new drawing logic, only a new playback
target (QSvgGenerator instead of the screen), sized to the element's own
content bounds via the existing elementSceneGeometricRect() helper.

## Hotspot cross excluded from the export

ElementScene::drawForeground() draws the red origin/hotspot cross on every
render() call, unconditionally -- it's an editing aid, not part of the
element being drawn, and diagram editor's SVG export has no equivalent
problem since Diagram doesn't draw one. Added a settable
hotspotVisible flag, defaulting to true (the existing editing view is
completely unaffected) and turned off only for the duration of the export
render() call.

## Verified end-to-end via a real Xvfb session, not just a build

Opened a real shipped element (en_60617_05_06_04.elmt, "Phototransistor"),
exported it, and rendered the resulting SVG back to a bitmap with a small
QSvgRenderer-based harness -- pixel-identical in shape to the element as
shown in the editor. Confirmed the file is valid XML and contains no
red/#ff0000 stroke (the hotspot cross did not leak in).

Then the case the whole "render live, not cached" decision was about:
opened the same element, drew a new line with the line tool, and exported
again *without saving*. The new line is present in the exported SVG.
git status on the source .elmt file after both exports shows it completely
untouched -- the export is read-only and reflects live, unsaved editor
state, exactly the property a cache-based implementation would have gotten
wrong.

Built clean, no new warnings.
2026-08-02 23:06:12 +12:00
Laurent Trinques 2d99ba67f1 Merge pull request #588 from Kellermorph/Fix-PLC-Manager
Fix-PLC-Manager
2026-08-01 15:30:10 +02:00
Kellermorph e91bab14fe Update 2026-08-01 14:26:39 +02:00
Laurent Trinques 6cdf60e2e7 Merge pull request #587 from ispyisail/feature-configurable-shortcuts
Add configurable shortcuts: Shortcuts preferences page + app-wide registry
2026-08-01 07:23:56 +02:00
ispyisail 9637f0ff9e Add live cursor-coordinate readout to the element editor status bar (#580)
Displays the cursor's scene position (same grid units as the parts'
X/Y property spinboxes) in a permanent status bar label, updated on
every mouse move. Addresses the overlapping-node mis-click case from
the originating forum report: with a live readout, precise pointing
no longer requires guessing against nearby z-ordered points.

ElementScene::mouseMoveEvent already computed the (optionally
grid-snapped) scene position on every move; it now also emits it via
a new mouseMoved(QPointF) signal, which QETElementEditor's status bar
label subscribes to.
2026-08-01 15:12:44 +12:00
Kellermorph 4c1f82f814 Fix-PLC-Manager 2026-07-31 21:02:07 +02:00
ispyisail 5275fb44fe Add configurable shortcuts: ShortcutManager registry + Shortcuts config page (#574)
Implements the first pillar of #574: a "Shortcuts" preferences page letting
users rebind, search and reset every keyboard shortcut in the app.

What it does
- New ShortcutManager singleton: every one of the ~95 setShortcut()/
  setShortcuts() call sites across qet.cpp, qetmainwindow.cpp,
  elementspanelwidget.cpp, autonumberingdockwidget.cpp, richtexteditor.cpp,
  qetdiagrameditor.cpp, qettemplateeditor.cpp and qetelementeditor.cpp now
  calls registerAction(target, id, category, default_sequence) instead,
  which applies the user's saved override (or the default) and remembers
  the target for later editing.
- New ShortcutsConfigPage, added to the existing "Configurer QElectroTech"
  dialog: a filterable table of every registered shortcut, grouped by
  category, each with a QKeySequenceEdit and a per-row reset button, plus a
  "reset all" button. Bindings are only persisted (via
  ShortcutManager::setSequence()) when the dialog is accepted.
- Conflict detection: rows whose currently-edited sequence collides with
  another row are highlighted with a tooltip naming the conflicting action.
- Overrides are stored under a "shortcuts/" QSettings group, one key per
  id, keyed to match the id (not persisted at all when equal to the
  hardcoded default), so a future QET version can safely raise a default
  for anyone who never customized it.

Design notes
- Targets are handled generically via QObject rather than QAction, since one
  call site (autonumberingdockwidget's "Configurer" button) is a
  QPushButton, not a QAction. Both declare an identical "shortcut"
  QKeySequence Q_PROPERTY, so registerAction() reads/writes it through the
  property system instead of needing a separate code path.
- Several live targets can share one id at once -- QET allows multiple
  windows of the same kind (diagram editor, element editor...) open
  simultaneously, each constructing its own QAction with the same id.
  setSequence() updates every live target for that id in one call, so a
  rebind takes effect in all open windows immediately, without restart.
- A shortcut's description is captured from its target's text() the first
  time that id is registered, then cached -- so the config page stays
  correct even after the owning window is closed. One consequence: a
  shortcut belonging to an on-demand window (element editor, title block
  editor, rich text editor) only appears in the list once that window has
  been opened at least once in the current session, since nothing has
  registered its id yet otherwise.

Testing
Full CMake build (qmake CONFIG+=no_kf5, Qt 5.15) compiles clean with zero
errors and zero new warnings. Verified end-to-end in a real running session
(Xvfb + xdotool):
- The Shortcuts page appears in Configure QElectroTech with the right icon,
  lists every always-registered shortcut with correct category/action name/
  current binding.
- The filter box correctly narrows the list, and correctly returns nothing
  for an action whose owning window hasn't been constructed yet this
  session (confirming the on-demand-registration behavior above is working
  as designed, not silently broken).
- Conflict detection correctly flagged a real pre-existing same-key overlap
  between "Supprimer" (delete selection, Del) and "Supprimer ce folio"
  (delete diagram from panel, Del) -- both highlighted with explanatory
  tooltips.
- Rebound "Manuel en ligne" to Ctrl+Shift+M, clicked OK: persisted under
  [shortcuts] in QElectroTech.conf, and the Aide menu's entry showed the new
  binding immediately, no restart needed.
- Reopened the dialog: the rebind was still shown. Clicked its per-row
  reset button, then OK: the settings key was removed entirely (not stored
  as "F1"), correctly falling back to the hardcoded default.

Retrofitting the Tab/Shift+Tab, select-all (#585) and Ctrl+G jump-to-element
(#586) shortcuts through this registry is left for a follow-up once those
PRs land, to avoid re-merging still-open branches into this one.

Developed with assistance from Claude (Anthropic).
2026-08-01 01:35:51 +12:00
Laurent Trinques 46cceb328e Merge pull request #582 from DieterMayerOSS/pr/font-legacy-format
Write font descriptions in a version-stable format (#553)
2026-07-31 10:30:49 +02:00
Laurent Trinques 717c89fa66 Merge pull request #562 from Kellermorph/PLC-Manager
PLC Manager
2026-07-31 09:05:30 +02:00
Dieter Mayer 68ffacc9e6 Salvage font descriptions written by Qt 6.11+ when parsing fails
QFont::fromString() of Qt 5.x and Qt <= 6.10 rejects the >= 19 field
descriptions QFont::toString() emits since Qt 6.11, silently leaving a
broken font at every read site. Add QETUtils::fontFromString(): try the
native parser first, and on failure re-compose the legacy 10/11 field
form from the known Qt 6.11 field layout (OpenType weight mapped back
to the legacy scale) so no font information stored in existing files is
lost. Also salvage the 21 field double-serialized descriptions left
behind by some historical builds (a complete legacy description
embedded as the family name of a second one) by taking the embedded
leading description, matching what the lenient parser of Qt 6.11+
resolves them to. All font read sites now go through the helper; on
failure the default font of the caller is left untouched instead of a
cleared family.

Verified end to end on a Qt 5.15 build: a project whose 53 font
attributes were rewritten into the 19 field Qt 6.11 format loads and
autosaves byte-identical to the original legacy file (family, sizes,
bold/italic/underline, style name all preserved), and a mixed file
containing the exact 21 field string from the issue comes back
normalized as "Caladea,9,-1,5,75,1,0,0,0,0,Bold Italic".

See issue #553.
2026-07-31 08:10:34 +02:00
Dieter Mayer 5da1fe5fc8 Write font descriptions in the stable Qt 5 10/11-field format
QFont::toString() is not stable across Qt versions: Qt 6.11 switched to
a 19-field format carrying OpenType weights, which QFont::fromString()
of Qt 5.x and Qt <= 6.10 rejects, leaving a broken font. Projects saved
by a Qt 6.11+ build were therefore unreadable by older builds.

Add QETUtils::fontToString() composing the legacy 10/11-field
description (weight mapped back to the legacy scale with the same
closest-match table Qt uses when parsing) and use it at every site that
stores a font description in a project, element, table config or
settings file. Every Qt version from 5.15 through 6.12-beta parses this
form correctly, so files stay readable by every QET build in
circulation.

See issue #553.
2026-07-30 21:45:36 +02:00
ispyisail b60e73d93b Fix #487: drag-selecting dynamic text fields silently converts their text source
updateForm() called on_m_text_from_cb_activated() directly, intending
only to enable the sibling widget matching the combo box's current
index ("For enable the good widget"). But that slot also loops over
every currently selected part and pushes an undo command overwriting
textFrom on any part that doesn't match, since it's normally only
reached via the combo box's own activated(int) signal (real user
interaction, never fired by programmatic setCurrentIndex()).

updateForm() runs on every selection change, so during a rubber-band
drag over dynamic text fields with different sources, each time a new
field enters the selection, the representative part's textFrom gets
force-applied to every other selected part - converting e.g. a
UserText field to ElementInfo mid-drag, before the user has released
the mouse or interacted with the combo box at all.

Split the cosmetic widget-enable logic into updateTextFromWidgetsEnabled(),
called from updateForm(). on_m_text_from_cb_activated() keeps the
part-mutating loop, now only reached from real user activation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 19:11:25 +12:00
Laurent Trinques 88962570a8 Merge pull request #569 from DieterMayerOSS/pr/parttext-alignment
Element editor: optional alignment for static texts
2026-07-28 17:45:43 +02:00