On GTK desktops (Mint, XFCE, GNOME) Qt hands QColorDialog to GTK's
chooser. Its "Custom" row is a recent-colours list kept by GTK: every
colour picked is pushed in on the left and the oldest drops out, so a
user's saved wire colours are lost (forum topic 3190). It also ignores
the custom colours QET saves (#918) and has no swatch grid for the
double-click to accept (#1172).
Pass DontUseNativeDialog at every colour dialog, so all platforms get
the dialog Windows already shows: 16 custom slots that change only on
"Add to Custom Colors", saved across restarts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
A new page in Configurer QElectroTech, "Barres d'outils", sets for
every window (folio editor, element editor, title block editor):
- the icon size: default, 16, 24, 32 or 48 px
- the buttons: icon only, text beside the icon, or text under it
- locking the toolbars so they can't be dragged out of place
OK applies it to the open windows at once. The defaults are Qt's
own, and a default value removes its key, so nothing changes for
anyone who never opens the page. A toolbar inside a panel is left
alone; only the window's own toolbars are locked.
New test tst_toolbarsettings: defaults change nothing, saved values
reach every toolbar of an open window, back to defaults removes the
keys.
Third stage of discussion #1319.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Shortcuts page now shows:
- each command's icon, and a Menu column saying where it is
("Projet › Scripts"); the text filter matches that too
- a category filter beside the existing Bound/Unbound/Conflicts one
- "Rechercher par touche": press a key combination and only the
commands using it are listed, however the key is spelled in the
user's language. A key also finds the two-key shortcuts it starts.
- "Copier la liste": the shown rows go on the clipboard as
tab-separated text with a header, so they paste into a spreadsheet
one cell per column
ShortcutManager::ShortcutInfo carries the icon and the first live
QAction so the page needs no second registry.
New test tst_shortcutspage covers the menu path, the columns, both
filters and the copied text.
Second stage of discussion #1319.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #849 the parts list has a row for every contact block (slave) and
terminal-type element. Users who draw the dots and bends where wires
branch as terminal-type symbols (114_connections) get one empty row per
junction: 109 of 151 rows on one reported cabinet.
Two options, both off by default so existing exports are unchanged:
- leave out the contact blocks: --no-slaves, "no_slaves" in qet_export,
or uncheck the new "Contacts esclaves" element type in the dialog;
- leave out the junctions: terminal-type elements with no label,
designation, manufacturer or manufacturer reference. --no-junctions,
"no_junctions", or "Laisser de côté les jonctions" in the dialog.
A terminal block with a label or a part number stays.
The element type filter had no box for slaves, so every query it built
left them out: the export dialog never listed contact blocks, although
the command line has since #849. The dialog now checks the new box by
default and gives the same rows as --export-bom. The box is unchecked by
default elsewhere, so nomenclature tables keep their rows.
docs/smart-device-bom.md still said slaves and terminals were excluded;
corrected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stacking added in #1287 tested the crosses' bounding rects, so
crosses whose frames or empty margins touched were raised although no
text was hidden (the list display case found in review). The texts each
cross really draws are now recorded while its geometry is built, and a
cross is raised only when one of its texts would be drawn over a text of
another one.
A new "Empiler les références dont les textes se chevauchent" checkbox
in the cross reference properties, per type, turns the stacking off;
the crosses of that type are then only centred, as before #1287. It is
saved in the project (xref attribute "stackoverlapping") and in the
settings, and is on when absent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Schemas now get saved with a UUID and do not have to be looked up according to the form. They can be renamed and it gets reflected in existing elements. The GUI for
editing them is now much easier, e.g. forms can be reshuffled. A formula can be applied. Many options now also for conductors and sheets.
Review of #1272: scorpio810 asked for a warning box for users; the inline
box added in 9a55939bb is replaced by a pop-up, as the element editor
gives for unnamed terminals. When OK in Settings > General or in Project
properties turns a rule on (a limit where there was none, or one wire
per folio report), a warning says the rules are experimental, may change
with settings to redo if wires and conductors become separate objects,
and can all be turned off in Settings > General. OK goes on. Changing a
limit that was already on, or turning rules off, shows nothing.
tst_wiringrules: when the warning is due (WiringRules::turnsRuleOn()).
Checked in the GUI from both pages, and that a plain OK shows nothing.
English for translators: "Warning"; "The wires-per-terminal rules are an
experimental feature. They count wires as QElectroTech represents them
today. They could change, and your settings need redoing, if wires and
conductors become separate objects in a future version. All these rules
can be turned off in Configure QElectroTech > General."
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
Review of #1272 (scorpio810, after arummler's note that the rules would
need redesigning if wires and conductors become separate objects): a
warning box, with the standard warning icon, at the top of the rules in
Settings > General and in Project properties. It says the feature is
experimental, counts wires as QElectroTech models them today, and that
the rules, and the user's settings, could change if wires and conductors
are separated.
English for translators: "Experimental feature. These rules count wires
as QElectroTech represents them today; they could change, and your
settings need redoing, if wires and conductors become separate objects
in a future version."
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
The limits were per project only. They are now set once in Settings >
General, under the master switch: the most wires per terminal and "one
wire per folio report". Every project follows them.
Project properties > "Conducteurs par borne" gets "Utiliser les réglages
de l'application", ticked by default, showing the application's values
greyed. Unticked, the project keeps its own values, saved in the project
as before, so a drawing that needs its own limit carries it to any
computer. A project's own "no limit" overrides an application limit too.
QETProject::wiringRules() now returns the rules in force (the project's
own, or the application's), so the code that checks a wire is unchanged;
projectWiringRules() returns what the project itself stores. A project
that follows the application still writes nothing, so it saves exactly as
before.
tst_wiringrules: which rules win, the save round trip of a project's own
"no rule", and through the real binary that the application's limit
refuses a wire unless the project overrides it or the master switch is
off (checked to fail with the application's rules ignored). ctest 55/55.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
Discussion #1158: a real terminal takes one or two wires (four with
double ferrules), a folio report is a virtual point that carries one, but
QElectroTech lets any number of wires be connected anywhere.
Project properties > General gets a "Conducteurs par borne" group:
- the most wires a terminal may take (0, the default, is no limit);
- "one wire per folio report".
When set, a new wire that would go past the limit is refused: the
terminal shows red while dragging, as for any refused link, and a tooltip
says why on release. Auto-connect on placing, moving or multi-pasting a
symbol skips full terminals, and qet.addConductor() refuses with its own
message. Wires already drawn, opening, pasting and undo are never
refused.
Settings > General gets a master switch, on by default, that turns every
rule of this feature off in every project; the project group is greyed
with a note while it is off.
The rules live in wiringrules.cpp. The project setting is saved as
<wiring_rules .../> only when a rule is on, so a project that never used
it saves exactly as before; an older version drops it, which means "off".
tst_wiringrules covers the rules, the save round trip and, through the
real binary, that a wire past the limit is refused unless the master
switch is off (checked to fail with the limit check removed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
A submenu under View (Affichage > Afficher) with one tick per kind:
symbol texts, wire texts, free texts, shapes, pictures, tables and
cross-references. Unticking one hides it on every folio of every open
project; the status bar says how many kinds are hidden. Session only,
not saved in the project.
Each item is tagged with its kind by its constructor (ShownKinds::tag),
so an item created while its kind is hidden starts hidden whatever
created it. A tag rather than type(): the cross-reference under a
contact's label is a plain QGraphicsTextItem.
Items that already hide themselves (wire text switched off, one text per
potential, a cross-reference snapped elsewhere) now go through
ShownKinds::setVisible(): the kind state can only veto a show, and
apply() re-shows only what it hid itself (hidden_key), never what an
item hid. Conductor::updateTextVisibility() replaces the same visibility
rule pasted in diagrampropertiesdialog.cpp and qetscriptapi.cpp.
Hidden items are not selectable (Qt), so Select All, copy and delete
skip them. Print, PDF and image export render the scene and leave them
out; the DXF export walks items itself and skips them through
ShownKinds::isHidden(). CrossRefItem::linkedChanged() keeps following
its slaves while hidden only by kind, so its label is right when shown.
Known limitation: QGraphicsScene::itemsBoundingRect() still counts hidden
items, so Zoom to fit and borderless image export keep their space.
Verified: tst_shownkinds (12 cases, two mutation checks) and ctest 55/55;
GUI hide/show of symbol texts, wire texts (incl. one text per potential),
free texts, shapes and cross-references returns pixel-identical folios;
with nothing hidden, --export-dxf of the 24 examples is byte-identical to
master (133 files) and --export-pdf renders identically (133 pages).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015FPuYPS4T7QuEwjNu22rXD
Pressing OK in Projet > Propriétés du projet without changing anything
marked the project modified and rewrote its defaults for new folios.
Besides the Page Num placeholder (fixed separately), four causes:
- Title block custom fields: since #271 the dialog offers the
template's variables for filling in; those left empty came back as
part of the context. Drop the ones not in the stored context.
- DiagramContext::remove() left the key's show flag behind, so a
context with a key removed never equalled one without it.
- Guides: applyConf() marked the project modified whether or not the
guides changed. Compare them like every other setting.
- Wire dash size and cross-reference offsets: the spin boxes cannot
show the stored default (dash size 1 under a minimum of 2; offset 0
under a minimum of 40 shown as "Default"), so the clamped value came
back. Keep the stored value unless the box shows something else, as
#1204 did for the wire panel.
Checked in the GUI (with the Page Num fix as well) on grafcet,
schema_indus and Projet_vierge: OK with no edit then Ctrl+S saves the
same file as Ctrl+S alone; master writes dash-size 1 -> 2, a
cross-reference offset 0 -> 40, and on Projet_vierge 22 empty custom
fields. New test for DiagramContext::remove() fails without the fix.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
In Projet > Propriétés du projet > Nouveau folio, the Page Num box shows
a "Créer un Folio Numérotation Auto" entry when the project has no folio
auto-numbering. Pressing OK, even without touching anything, returned
that entry's text as the numbering's name: it was saved in the project
as auto_page_num (in the interface's language), and since it differed
from the stored empty value the project was marked modified.
When the project has numberings, an empty stored value cannot be shown
at all, so the first numbering came back instead.
Return the stored value unless the user picks an entry (activated() is
only emitted for a user's choice), and never return the placeholder.
Checked in the GUI on grafcet, schema_indus and Projet_vierge: after OK
with no edit and Ctrl+S, master saves auto_page_num="Créer un Folio
Numérotation Auto"; this branch keeps auto_page_num="". An edited field
on the same page (default author) is still saved.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The conductor properties dialog disables the "Texte visible" checkbox
when the folio has "Afficher un texte de potentiel par folio" on, but it
also hides that option, so nothing told the user why the box could not
be ticked. A wire saved with its text off then looked impossible to fix.
The locked box's tooltip now names the folio option and where to change
it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QElectroTech now writes qet-assistant.json in the standard data folder
when an editor opens, and again whenever the stored scripts or the
scripting setting change: its version and program, every folder (data,
settings, scripts, the element and title block collections), which
features are on, every call a script can make (QetScriptApi::signatures(),
apiSignatures() without a running script), and the stored scripts with
their ids, files, icons and shortcuts, plus those refused and why. On
quit it says nothing is running any more.
The qet MCP server reads it rather than guessing each folder per
platform, which is wrong as soon as QElectroTech runs with --data-dir:
the file stays where the server can find it and names the folders
actually in use. Readable by the user only.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A new setting, Configurer QElectroTech > Général > "Autoriser un assistant
IA à agir sur le projet ouvert", off by default. Off, nothing changes:
no channel is opened. On, every start shows a warning first -- Continuer,
Pas pour cette session, or Désactiver -- and nothing can connect until
the user answers Continuer. It waits for any other start-up question to
be answered, so the two never stack.
Accepted, LiveServer opens a local socket only the user's account can
use, with a random name and token written to live-session.json in the
data folder for the qet MCP server, and removed when the channel closes.
One JSON request per line: status (project, folio on screen, selection,
last undo step, stored scripts), run_script and run_stored. Requests are
queued out of the socket handler before they run (the lesson of PR #861).
Each run is one undo step named "Assistant : <name>". The status bar
shows the mode and the assistant's last action with a ✓ or ✗ and the
time, and an Arrêter button that closes the channel for the session.
Unticking the setting closes it at once.
QetScripting::runSource() runs script text and, for a live run, returns
what qet.log() wrote, the error with its line and the undo step instead
of showing boxes; qet.showMessage() is logged rather than opening a box
nobody asked for.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #1205:
- The scene gives no order for its selection, so the "first" wire whose
values the panel shows could change between two selections of the
same wires. The wires are now sorted top to bottom, then left to right.
- A text field the selected wires do not agree on (function, section,
cable...) is shown blank with the hint "Plusieurs valeurs". Typing any
value there, including the first wire's own, now differs from what was
shown, so it reaches every wire: 1.5 mm² on a 1.5 and a 2.5 wire works.
- The conductor text is locked while several wires are selected: the same
number on all of them would make duplicates. "Apply to all conductors
of this potential" with one wire selected still sets the number on the
whole potential.
- One edit of N wires emitted N signals, each reloading the panel. They
are now gathered into one reload, which matters since a reload reads
every selected wire to find the mixed fields. Selections and targets
are de-duplicated with sets, and a wire reached through an earlier
wire's potential is not walked again. An edit that changes nothing
returns before any potential is walked.
The rules move to sources/conductormultiedit.h, templates over the wire
type, so tst_conductormultiedit can check them against a fake wire:
order, targets with and without potentials, one undo step and its redo
for three wires, and the mixed fields. tst_conductorapplychanges now
gives the other wire the opposite value in every boolean field, so
copying one by mistake fails the test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Selecting more than one wire left the Selection properties panel empty,
and so did a box selection over a single wire, because it also picks up
the wire's number label.
Now the panel opens for any number of selected wires. A selected wire
label counts as its wire, once, so a box drawn over wires works. The
fields show the first wire's values, a line above them says how many
wires are selected, and an edit is applied to each wire field by field:
setting the function on ten wires leaves each with its own number,
cable and section. With "apply to all conductors of this potential"
ticked, the potentials of all the selected wires follow the same rule.
Each edit is one undo step.
Fields whose values differ between the selected wires are not marked as
such; that can follow if wanted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With "Show the properties of a selected conductor in the Selection
properties panel" switched on, editing a wire there could change things
the user never touched:
- Enter in a field (Function, Section...) is not used by the line edit,
so it reaches the checkable "Multifilaire" group box around it, which
takes it as a click. The wire was switched to single-line, gaining
ground, neutral and phase symbols. The modal dialog never shows this
because its OK button takes Enter first.
- Every edit wrote back the whole set of properties as the widget holds
them, so a value the widget cannot show exactly was rewritten: a dash
size of 1 became 2.
The panel now swallows Enter at its checkable group boxes, and writes
only the fields that differ from what it showed, through the new
ConductorProperties::applyChanges(). "Apply to all conductors of this
potential" uses the same rule, so the rest of the potential keeps its
own values too.
tst_conductorapplychanges checks each field on its own: change that one
field, and a wire whose every field differs takes it and keeps the rest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>