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>
Where two wires cross without being connected, a project can now draw a
small arc (a hop) on one of them, instead of the user inserting a jump
symbol and splitting the wire. It is a project setting, off by default:
Project properties > Général > "Croisements de conducteurs", with no
hops, hops on horizontal wires, or hops on vertical wires. Choosing the
orientation rather than following drawing order keeps a project
consistent.
Only the drawing changes: no element is added and no wire is split. A
wire that ends or bends on another one is a junction and never hops,
and a crossing too close to the end of a segment for the arc to fit is
drawn plainly. PDF, SVG and image export and printing show the hops,
since they paint through Conductor::paint(); DXF export, which writes
the segments itself, does not.
The setting is saved as <wire_crossings hop="..."/> under the project
root, next to <usage>, and only when hops are on, so a project that
never used them saves exactly as before.
The geometry is in wirehops.cpp, free of any graphics item, and tested
on its own. Conductor::paintedPath() feeds it the conductors of the
folio from a snapshot of their scene points, rebuilt only when a
conductor changes shape, moves, or enters or leaves a folio; each hop
path is cached the same way. Asking the scene for the conductors in a
rect instead strokes every candidate's shape, which made a 366-wire
folio render 0.6 s slower; with the snapshot the difference is within
measurement noise.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ticking or unticking "Afficher un texte de potentiel par folio" in
Folio > Properties only assigned Diagram::defaultConductorProperties.
Nothing recalculated the conductor texts, so texts hidden by the option
stayed hidden after it was turned off (and duplicates stayed visible after
it was turned on) until each wire was edited or the project was reopened.
That made the option look broken, which is part of what #344 reports.
When the option changes, reset each conductor's text visibility from its
own properties, then run calculateTextItemPosition() on every conductor of
the folio so the option is applied again from scratch.
Checked in the GUI on examples/industrial.qet folio 4 (26 wires with text,
19 potentials), master vs this commit: unticking now shows the hidden
texts immediately, ticking hides the duplicates immediately; master's
drawing does not change in either direction.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only one conflict: the include block of
sources/ui/configpage/generalconfigurationpage.cpp, where upstream adds
editor/terminalnamecheck.h next to the two includes of the prefix
editor. All three are kept. The file list in
cmake/qet_compilation_vars.cmake merged itself this time.
Review findings on the prefix editor:
- OK without touching anything changed the file: every row was written
back, so an explicit <prefix/>, which reads as an empty field and
cancels the inheritance, was dropped and that folder started
inheriting its parent's prefix again. A row is now written only when
it was edited or no longer holds what the file has, and the two kinds
of empty field look different: hasPrefix() tells an explicit
<prefix/> from a missing one, which is what the field hint shows.
- load() copied a broken file aside before the user had chosen
anything, so every "Corriger le fichier" left a .bak behind while the
message said nothing had been modified. The copy is now made by
save(), right before the file is replaced: repairing or cancelling
leaves nothing behind, and a copy that cannot be made stops the write
rather than destroying the only copy.
- The button followed the combo box only for "Parcourir...": put back
on "Par defaut" it fell back to the previously saved path instead of
the default one. The directory of the entry being displayed is now
used, "Par defaut" being dataDir()/elements/.
The text properties showed and edited the top-left corner of a text,
whatever its alignment, and changing the alignment did not move the
text. A right-aligned label next to a symbol therefore needed a
different X for every text length to keep the same gap (#1155).
Position X/Y is now the anchor point: the point of the text chosen by
the alignment (right edge for "right", middle for "centre"...). Typing a
position puts that point there, and changing the alignment moves the
text so that the new anchor point is on the same X/Y. It is the same
point that already stays fixed when the text changes.
Applies to the element text properties on a folio and to the text
field properties in the symbol editor. The saved x/y is still the
top-left corner, so projects and symbols load and save unchanged and
look the same; only the numbers shown for texts that are not top-left
aligned change.
The geometry is in textanchor.h, shared by DiagramTextItem and
PartDynamicTextField, and tested in tst_textanchor.
Not changed: static texts of the symbol editor (PartText), whose
position is tied to the font baseline; texts inside a text group, which
have no position or alignment of their own; rotation still pivots on
the top-left corner (or the centre), not on the anchor.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the F2 conductor colour dialog and the toolbar's "Other colour..."
dialog, a double-click on a basic or custom colour swatch now chooses it
and closes the dialog, as OK does (forum topic 3190). Qt's dialog only
selects the swatch on a double-click.
ColorDialogDoubleClick filters the dialog's QWellArray swatch grids,
found by class name once the dialog is shown, because Qt builds them
only then when a native dialog was offered but not shown. Where the
platform's native colour dialog is used instead (macOS, some Linux
desktops) there are no swatches to watch and nothing changes. The
toolbar dialog is now an instance rather than QColorDialog::getColor(),
so the filter can be installed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts in cmake/qet_compilation_vars.cmake only, where upstream added
terminaluuids.cpp/.h next to the qetlabelsfile.cpp/.h this branch adds :
both are kept, qetlabelsfile first to stay alphabetical.
The prefixes of a collection's folders live in a qet_labels.xml that so
far could only be edited by hand, and a hand-edited file is easy to
break: one extra </category> and the file stops being well formed, which
the lookup answers with "no prefix at all". Labels then degrade
silently, without any error anywhere - the file is simply ignored. Add
a way to edit it from the settings.
- "Configurer les préfixes…" next to the user collection path opens
PrefixConfigurationDialog, which lists every folder of that
collection, subfolders included, one line edit each, with "Tout
déplier"/"Tout replier" and OK/Abbrechen. It writes on OK only :
cancelling leaves the collection exactly as it was, and an emptied
field drops the <prefix> again so the folder goes back to inheriting
its parent's.
- QetLabelsFile owns the reading, scanning, structure building and
writing of the file. prefixFromLabelFile() moves there unchanged from
assignvariables.cpp as prefixForPath(), so the lookup used by label
assignment and the one used by the dialog are one piece of code.
- Entries whose folder no longer exists on disk are offered as
Conserver or Supprimer and only applied on OK.
- An unparsable file is copied to qet_labels.xml.bak first, and the
dialog then reports the line and column of the syntax error, with
"Corriger le fichier" as the default choice - such a file may be one
forgotten tag away from being valid - and rebuilds the whole
structure only when "Reconstruire" is picked. A broken file that
cannot be backed up is refused rather than overwritten.
The scan reads non-hidden directories recursively in name order,
without following symlinks. A collection without any subfolder has
nothing to configure and says so instead of opening an empty dialog.
Tests: a standalone harness kept outside the tree (84 checks :
structure, inheritance, explicit empty prefix, orphan handling, broken
file, wrong root element, broken file whose backup cannot be written,
reload after save) and the dialog driven offscreen (29 checks,
including "reject creates no file"). ctest 27/28, the failing
tst_menubarkeyboard being the headless F10 test, unrelated to this.
The new strings are French source strings like the rest of the code;
the .ts files are left to the translation update.
Discussion #598, reviving PR #654. The crash-recovery backup written
every 20 minutes went to a single file. If the project was already in a
bad state when a backup ran, that bad state replaced the only recovery
copy.
QETProject now writes the backups in turn to three KAutoSaveFile slots
(BackupGenerations), so one bad write only replaces the oldest
snapshot. Scope is crash recovery only; the opt-in autosave is
unchanged.
After a crash, the recovery prompt groups the snapshots by project and
offers one row per project with a list to pick the snapshot to reopen,
newest selected by default. The snapshots not picked are deleted.
Ported onto current master: writeBackup() keeps the "skip if nothing
changed" check (bugtracker #273) and offerBackupFiles() keeps its place
after the stale-file filter and before the crash report (#901).
Tested with the backup interval shortened to 4 s (test build only):
after three changes, master holds one recovery file, overwritten each
time; this branch holds three, with 4, 5 and 6 folios. After killing
QET, the prompt lists the project; picking the oldest snapshot reopens
4 folios, the default reopens 6. Twice each. ctest 34/34 with and
without KDE Frameworks; the carried-over KAutoSaveFile test passes in
the nokde build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QETElementEditor, QETDiagramEditor and QETTemplateEditor already
persist their geometry via QSettings; none of the modal QDialog
subclasses did, so any dialog resized to see more of its content
(Search and Replace, Diagram properties, Export, ...) is back to its
default size the next time it's opened.
Adds QET::trackDialogGeometry(), one call at the end of each dialog
constructor (after any default resize()), following the same
restoreGeometry()/saveGeometry() pattern as the three editors above,
stored under [dialoggeometry] and keyed by class name by default. An
explicit key is used for PropertiesEditorDialog, a single class
templated over several unrelated wrapped editors, so they don't all
fight over one saved size.
Covers the 36 dialogs of the original change (#691) plus seven added
since: RenumberElementsDialog, MaterialEntryDialog, AiAssistantDialog,
DuplicateOffsetDialog, ImageTransparentColorDialog, PdfPagesDialog and
WiringListDialog.
Deliberately not touched: BackupDialog and ImageCropDialog, which
setFixedSize() themselves, and MaterialSelectionDialog, which already
restores its own size.
A size saved while the dialog sat partly off-screen is restored on
screen: restoreGeometry() moves it back inside the available screen
(checked: saved at 1502,972 on a 1600x1000 screen, reopened at 600,317).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
masterpropertieswidget.cpp set an inline "background-color: #f0f0f0"
stylesheet on the disabled type combo box in the PLC master I/O
table. Qt already renders disabled widgets correctly without help;
the hardcoded light color just breaks under a dark palette, showing
a bright box in an otherwise dark dialog. Dropping the stylesheet
lets it render like every other disabled widget in the app.
Discussion #1157. IEC 61666 §4.1 requires each terminal to be
identified unambiguously within its object, so two terminals of one
element must not share a name.
On save, the element editor now:
- refuses to save when two terminals share a name, lists the names
("N ×3") and selects those terminals;
- warns, and still saves, when a terminal has no name. Folio reports,
conductor definitions and thumbnails are skipped.
Names are compared after trimming surrounding spaces, case sensitive.
Settings > General > Editor has a new checkbox, on by default, that
turns both checks off (elementeditor/check-terminal-names).
--check-elements applies the same rule: repeated names are a FAIL,
missing names a WARN. It ignores the setting, since it is an explicit
check. On the shipped collection this reports 82 FAILs, the elements
that repeat a terminal name today.
The rule lives in the header-only editor/terminalnamecheck.h, shared
by both, and is unit tested by tst_terminalnamecheck.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The configuration names "python" or "python3", or the Python the Windows
installer can add. When none of those can run, the assistant fails with
an error far from the cause, so the dialog now says so in bold, with what
to do: tick "Python pour l'assistant IA" in the installer or install
Python (Windows), or install Python 3 from the system's packages.
Windows 10 and 11 put a python.exe in WindowsApps that only opens the
Microsoft Store, so a PATH search alone reports Python where there is
none. A result there is reported as possibly that shortcut. Backslashes
are converted explicitly, not with QDir::fromNativeSeparators(), which
leaves them alone off Windows and so could not be tested here.
tst_aiassistantsetup: 17 cases (8 new: the bundled Python is taken
without looking on PATH; none, python.org, the Store shortcut with either
separator, and a Linux folder named WindowsApps). Each of the 4 new rules
was removed in turn and the test failed. ctest 32/32. In the GUI, the
same install layout shows the warning with no python3 on PATH and no
warning with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dialog showing the configuration an AI assistant needs to start
QElectroTech's MCP server (misc/qet-mcp), with this installation's paths
filled in: pick the assistant (Claude Desktop, Claude Code, GitHub
Copilot in VS Code, Cursor, Gemini CLI, Codex CLI, LM Studio), the
drawings folder the assistant may use, and whether it may edit (off by
default). It says where the text goes, warns that text inside a project
from someone else can steer an assistant, and copies the text. It writes
nothing and starts nothing.
AiAssistantSetup finds the server beside the running program, in the two
places the packages put it (<root>/mcp beside <root>/bin on Windows,
<prefix>/share/qelectrotech/mcp beside <prefix>/bin otherwise), and the
Python the Windows installer can add. When there is none, the dialog says
the server is not installed with this version and links the guide.
The configuration is written with QJsonDocument, so Windows paths are
escaped correctly; Codex CLI gets TOML.
tst_aiassistantsetup (9 cases): both layouts, no server, the bundled
Python on Windows only, valid JSON for every JSON client with paths that
parse back unchanged, the "servers" key for VS Code, "type" only where
wanted, editing off unless allowed, escaped TOML. Each of 8 rules was
removed in turn and the test failed. ctest 32/32.
Checked in the GUI (Xvfb): Help menu opens it; from a build tree it
reports the server missing and disables Copy; from an install layout it
fills the paths, and the text Copy put on the clipboard, used unchanged
as a Claude Code configuration, ran a real qet_project_info call.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two problems with a custom variable newly added to a title-block template:
1. Find/Replace > Folio > Custom showed an empty table, so the user had to
know and type each variable name. It now lists every custom variable the
folios already carry plus those their templates use, with empty values.
An empty value now means "leave unchanged", like every field of the main
tab; only the variables actually filled in are written to the folios.
2. The title block showed the variable's own name ("%doc-type") until the
folio's properties were opened, because interpreteVariables() only
replaces names present in the context. Placeholders in the template text
that no key resolves now render blank, as auto-added unset ones already
did since #973. Only the template's own text is considered, so a value
that contains "%something" is never touched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up to #1088, covering its review comments and one behaviour
change found while testing the feature:
- MaterialList::load() names the columns from the machine key line when
the file has one, instead of from the translated label line above it.
A catalogue written in another language fills the element fields
again, and saving no longer replaces the key line with labels.
- The entry picked after "New entry" is found by comparing the columns
one by one instead of comparing the two maps as a whole: the entry
form leaves the empty columns out, so the record never matched the
line that had just been written and the search was cleared for
nothing. The search is now only given up when it really hides the new
line.
- Applying a catalogue entry pushes an undo command only when the live
edit is on. In the properties window, where there is none, the fields
wait for "Apply", so "Cancel" gives the element its own values back
instead of leaving the picked part in place.
- Cells a file holds past the header are kept in MaterialRecord::extra
and written back, so appending an article never shortens a line.
- An empty cell of a column describing the article itself (MaterialList::
isArticleBound: description, designation, manufacturer, order number,
supplier, model, ratings, dimensions, auxiliary block) clears the
field, so an element never keeps the manufacturer of the part picked
before. An empty cell of any other column (function, comment, notes,
plant, location, quantity, unity), and any column the file does not
hold at all, leaves the field alone.
- Comments left where the review asked for them: the corner button
lookup, the ';' separator fallback, the search filter cost.
The element description dialog only offered typing, so every article of
a catalogue had to be copied in by hand into the Artikelbeschreibung
row of each block, over and over.
Settings > General now keeps the path of a CSV material list (Créer...
writes a template with the header lines), and the Artikelbeschreibung
row of every block of the Bauteil dialog shows a "..." button opening a
searchable listing of that file. "Appliquer" fills the fields of that
block only -- the main block gets everything but label and formula, an
auxiliary block gets description, number, manufacturer, references,
supplier, quantity, unit and additional info -- and a cell that is
empty in the file never erases a value already in the element. The
symbol editor is left alone.
- sources/materiallist/: CSV reading and writing (UTF-8 BOM, ';', every
field quoted, atomic write through QSaveFile), two header lines
(translated labels then the canonical English keys), the selection
window and the new entry form.
- The selection window reads the file again every time it opens, keeps
its size, column widths, column order and sort between openings,
shows every column of the file, scrolls all four directions with the
wheel (Shift + wheel moves the columns) and puts back the order of
the file when the corner above the row numbers or a row number is
clicked.
- German translations for the new strings in lang/qet_de.ts.
conductorpropertieseditorwidget.cpp, from the #500 work, included
<KColorButton> unconditionally, so a build with BUILD_WITH_KF=OFF stopped
at "KColorButton: No such file or directory". Include the nokde stand-in
there instead, as dynamictextfieldeditor.h and terminaleditor.h do. It
has the same changed() signal the file connects to.
Checked on Ubuntu 22.04 (Qt 6.2.4, BUILD_WITH_KF=OFF): the file fails on
master and compiles with this change; together with #1085 the whole tree
builds and links. Builds with KDE Frameworks compile the same line as
before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
#1051 replaced the filtered tree with a ranked flat list. A new checkbox
in Settings > General, "Afficher les résultats de recherche sous forme de
liste triée" (elementscollection/search-flat-list, default on), keeps the
ranked list; unticked restores the pre-#1051 filtered tree search.
The Insert picker and shortcut bar call rankedSearch() directly and are
unaffected. Down/Enter from the search field only apply to the flat list.
Requested by scorpio810 on #1051.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
A picture can now carry a caption, set from its properties panel
("Libellé"). It is drawn centred under the picture at the folio's
normal text size whatever the picture's scale, turns with it, and
moves, copies and prints with it because the picture itself paints it.
Clicking the caption selects the picture.
Saved as a "label" attribute on <image>, written only when non-empty:
a project without labels saves byte-for-byte as before, and older
versions open a labelled project and simply ignore the caption.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
Showing a selected conductor's properties in the selection-properties
dock is now a preference, on the General page under Appearance:
"Afficher les propriétés d'un conducteur sélectionné dans le panneau
Propriétés de la sélection". It is off by default, so selecting a
conductor does what it did before unless the user turns it on.
This replaces the View-menu toggle, which defaulted to on; that entry
is dropped in the merge with master. Same setting key
(diagrameditor/conductor_properties_panel).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>