Let a script duplicate elements, with the conductors between them

duplicateElements(fromFolio, [uuids], toFolio, x, y)
  selectedElements(folio)

What Ctrl+C and Ctrl+V do: the named elements are selected, serialised
with Diagram::toXml(false, true), the previous selection is put back, and
the copy is pasted with Diagram::fromXml() and a single
PasteDiagramCommand. A conductor is copied only if both its ends are among
the copied elements. As on a paste in the application, the copies come
without labels or their conductors' wire numbers (measured: empty on
both). One undo removes the elements and the conductor together.

Three properties found by measuring rather than assuming:

- Position is the top left of the pasted group's bounding rectangle, so an
  element's own origin ends up offset by its hotspot: +20, +30 for a coil,
  identical across two trials. (0, 0) is not a position; Diagram::fromXml
  treats the origin as "keep the source coordinates".
- The application's pasted list is in scene order, not the order the
  elements were named. Asking for the elements at x = 700, 100, 900 returned
  the copies of 100, 700, 900, so a caller pairing copies with sources by
  index was wired to the wrong ones with no error. A paste is a pure
  translation, so sorting sources and copies by position pairs them, and
  the result is returned in the order asked. Checked with a scrambled
  request over a zig-zag layout: every copy is the identical translation
  (-30, -20) from the source at its index. Two elements at one point cannot
  be told apart; if the counts disagree it says so and returns the
  unpaired list rather than guess.
- Copying works by selecting, so the previous selection is given back;
  selectedElements() exists to make that checkable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
ispyisail
2026-09-21 22:47:48 +12:00
parent 279b001a16
commit 2772b690e8
2 changed files with 131 additions and 0 deletions
+22
View File
@@ -186,6 +186,23 @@ class DynamicElementTextItem;
selected, so it is a separate, explicit call. Folio auto-numbering is
not offered: in the application it spawns whole new folios from a
context, which is a different operation from labelling.
- @b Duplicating: copy elements, together with the conductors that run
between them, to a position on the same or another folio, through
Diagram::toXml() and fromXml() and PasteDiagramCommand -- what Ctrl+C
and Ctrl+V do, so a paste behaves as a paste does there: the copies
come without their labels and without their conductors' wire numbers,
which the application clears on paste (measured: '' on both).
The position is the top left of the pasted group's bounding rectangle,
so an element's own origin ends up offset from it by its hotspot
(measured: +20, +30 for a coil); (0, 0) is not a position but means
"keep the source coordinates", as Diagram::fromXml() treats it. The
result lists the copies in the order the elements were named --
the application's own list is in scene order, and a caller pairing by
index would otherwise be wired to the wrong copies -- paired by
position, which a paste preserves, so two elements at the same point
cannot be told apart. A conductor is copied
only if both its ends are among the copied elements. The previous
selection is put back afterwards, since copying works by selecting.
- @b Images: place a picture from a file. The pixels are copied into
the project, which stores them inline in the .qet -- the saved file
does not refer to the original path, so it opens on another machine,
@@ -377,6 +394,10 @@ class QetScriptApi : public QObject
int textIndex, const QString &property) const;
Q_INVOKABLE bool deleteElementText(int folioIndex, const QString &elementUuid, int textIndex);
// -- copy elements (with the conductors between them) to a position --
Q_INVOKABLE QStringList duplicateElements(int fromFolioIndex, const QStringList &elementUuids,
int toFolioIndex, double x, double y);
// -- folios --
Q_INVOKABLE int addFolio();
Q_INVOKABLE bool setFolioTitle(int folioIndex, const QString &title);
@@ -389,6 +410,7 @@ class QetScriptApi : public QObject
// -- navigate and message --
Q_INVOKABLE bool selectElement(const QString &elementUuid);
Q_INVOKABLE void deselectAll(int folioIndex);
Q_INVOKABLE QStringList selectedElements(int folioIndex) const;
Q_INVOKABLE bool zoomFit();
Q_INVOKABLE bool zoomToContent();
Q_INVOKABLE bool zoomReset();