Bring the wiki up to date with features merged since 19 September

Stale notices: drop #1073's pending markers (merged), and the #927 and
#929 "until it merges" notes (both merged a week ago).

New pages: "3D mouse" (#1022-#1035) and "Pictures on a folio" (label
from #1068, save cache from #1067, and the existing crop, transparency,
mirror and handle features, none of which were documented).

Updated: text grid for dragged texts (#1040) in mouse_modifiers,
grid_and_element_size and preferences; conductor colour toolbar button
(#929, #1005) in conductors; full contact comb option (#1010) and the
correct meaning of terminalCount in element_linking; three new tables,
drawing_item_view, item uuids (#1065) and read-only queries (#1066) in
project_database and the XML reference pages; folio background colour
remembered between runs (#1011); element information suggestions (#1021).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
ispyisail
2026-09-28 06:15:57 +13:00
parent 2a946a4b21
commit 7a91c76bf4
18 changed files with 546 additions and 49 deletions
+188
@@ -0,0 +1,188 @@
# 3D mouse (SpaceMouse)
A 3Dconnexion 3D mouse — SpaceMouse, SpacePilot, SpaceNavigator and the like —
can pan and zoom QElectroTech's folios and the element editor with one hand,
leaving the other on the ordinary mouse for drawing. Its buttons can run any
QElectroTech command that has a keyboard shortcut.
Support was asked for, and is still discussed, in
[discussion #599](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/599).
Reports from real devices are welcome there: see §6.
---
## 1. What it does
| On the device | In QElectroTech |
|---|---|
| Slide the cap left/right, forward/back | pans the view |
| Push/pull the cap (default), or twist it (setting) | zooms |
| Tilt | nothing |
| A button | the command you bound to it, if any |
It acts on whichever window is in front: the current folio of the schematic
editor, or the element editor's drawing. Zoom stops at the same limits as the
mouse wheel.
Nothing happens on a button press until you bind that button (§3). There is no
default binding.
---
## 2. Which builds have it
3D mouse support is a compile-time option, off by default. How the device is
read depends on the build:
| Build | Reads the device through | Needs |
|---|---|---|
| Windows package | USB directly (hidapi) | nothing extra; no 3Dconnexion driver is required |
| macOS package | 3DxWare when it is installed and running, otherwise USB directly | nothing extra |
| Flatpak | USB directly (hidapi) | read access to `/dev/hidraw*`, see §5 |
| Snap | spacenavd | the `spacenavd` daemon running |
| Linux distribution packages, own builds | whatever the packager chose | see §7 |
If the **Souris 3D** page is missing from the preferences (§3), your build does
not have 3D mouse support.
On macOS, while QElectroTech is the front application, 3DxWare's own actions
are switched off in it, so the view does not move twice.
---
## 3. Settings
*Edit → Preferences*, page **Souris 3D** (*3D mouse*).
### Mouvement (*Motion*)
| Setting | Range | Default | Does |
|---|---|---|---|
| **Vitesse de déplacement** (*Pan speed*) | 10–400 % | 100 % | how fast the view pans |
| **Vitesse du zoom** (*Zoom speed*) | 10–400 % | 100 % | how fast it zooms |
| **Zoomer en** (*Zoom by*) | *Pousser / tirer le capuchon* (push/pull the cap), *Tourner le capuchon* (twist the cap) | push/pull | which movement zooms |
| **Zone morte** (*Dead zone*) | 0–200 | 0 | movements smaller than this are ignored; raise it if the view drifts while you are not touching the device |
| **Inverser le déplacement horizontal** | on/off | off | reverses left/right |
| **Inverser le déplacement vertical** | on/off | off | reverses forward/back |
| **Inverser le zoom** | on/off | off | reverses zoom in/out |
The speed on screen does not depend on how often the driver sends updates, so
the same setting feels the same on every system. An equal push and pull cancel
out exactly.
### Boutons (*Buttons*)
A table of button number → command:
1. Click **Ajouter une association** (*Add a binding*).
2. Set **N° bouton** to the button's number.
3. Pick the command under **Action**. The list holds every command that has a
shortcut in QElectroTech, grouped by editor.
4. Click **OK** to save.
The number a button sends depends on the device and on how it is read. The
device's documentation may give it; otherwise try 0, 1, 2… in turn. The button
at the end of a row removes the binding.
---
## 4. Where the settings are kept
In QElectroTech's own settings, not in any project: under `spacemouse/motion/`
for the motion settings and `spacemouse/buttons/` for the bindings. They apply
to every project, and to both editors.
---
## 5. When nothing happens
| Symptom | Check |
|---|---|
| No **Souris 3D** page in the preferences | the build has no 3D mouse support: §2 |
| Snap: the device does nothing | `spacenavd` is installed and running (`systemctl status spacenavd`) |
| Flatpak: the device does nothing | your user can read the device: `ls -l /dev/hidraw*`. On many distributions these nodes are readable by root only, and a udev rule is needed (below) |
| The view drifts on its own | raise **Zone morte** |
| It moves the wrong way | the **Inverser…** settings |
| A button does nothing | it is not bound yet, or bound to the wrong number: §3 |
A udev rule giving the logged-in user access to 3Dconnexion devices, for the
Flatpak or any build using the USB backend on Linux. Save it as
`/etc/udev/rules.d/70-3dmouse.rules`:
```
KERNEL=="hidraw*", ATTRS{idVendor}=="256f", TAG+="uaccess"
KERNEL=="hidraw*", ATTRS{idVendor}=="046d", TAG+="uaccess"
```
`256f` is 3Dconnexion; `046d` is Logitech, which sold the older models. Then
run `sudo udevadm control --reload && sudo udevadm trigger` and replug the
device. QElectroTech looks for a device every three seconds, so it does not
need restarting, and it reconnects on its own after the device is unplugged.
---
## 6. Helping with a recording
The USB backend decodes each device model's raw reports itself. A short
recording from a real device lets that model be tested. The script
`misc/spacemouse-capture.py` in the source tree guides you through a few
movements, saves one `.json` file, and sends nothing anywhere. It runs on
Linux, macOS and Windows with only Python 3.
```bash
curl -LO https://raw.githubusercontent.com/qelectrotech/qelectrotech-source-mirror/master/misc/spacemouse-capture.py
python3 spacemouse-capture.py --help # step-by-step instructions for your system
python3 spacemouse-capture.py --seconds 3 # record, three times the default time per step
```
On Linux, run it with `sudo`, for the reason in §5. Attach the file to
[discussion #599](https://github.com/qelectrotech/qelectrotech-source-mirror/discussions/599).
One recording per device model is enough.
---
## 7. Building it in
Two CMake options:
| Option | Values | Default |
|---|---|---|
| `QET_ENABLE_SPACEMOUSE` | `ON`, `OFF` | `OFF` |
| `QET_SPACEMOUSE_BACKEND` | `auto`, `spnav`, `hid` | `auto` |
| Backend | Reads through | Library (pkg-config) |
|---|---|---|
| `spnav` | the spacenavd daemon, Linux | `libspnav-dev` (`spnav`) |
| `hid` | USB directly, any system | `libhidapi-dev` on Linux (`hidapi-hidraw`), MSYS2 `mingw-w64-ucrt-x86_64-hidapi`, Homebrew `hidapi` |
| `auto` | spnav on Linux when libspnav is found, hid otherwise | |
On macOS the 3DxWare backend is always added as well. It loads 3DxWare's
library at run time and needs nothing to build.
```bash
cmake -B build -DQET_ENABLE_SPACEMOUSE=ON -DQET_SPACEMOUSE_BACKEND=hid
```
If the chosen backend's library is not found, CMake prints a warning and builds
**without** 3D mouse support rather than failing. Check the configure output
for a line like `QET_ENABLE_SPACEMOUSE ON (backend: hidapi 0.14.0)`.
---
## 8. Limitations
| Limitation | Detail |
|---|---|
| Pan and zoom only | tilting the cap does nothing; there is no rotation of the folio |
| Button numbers are raw | there is no "press the button to bind it"; find the number by trying |
| 3DxWare app events | on macOS, only raw button presses are read, not the named actions newer 3DxWare versions send |
| Hardware coverage | tested on the devices reported in discussion #599; other models may need a recording (§6) |
---
## See also
- **[Preferences reference](preferences)** — the other preference pages
- **[Finding your place on a folio](navigating_folios)** — going to a cell, keeping the headers in sight
- **[Keyboard-only control](keyboard_control)** — the commands a button can be bound to
- **[Building from Source](building)** — the full build instructions
+5 -1
@@ -38,7 +38,11 @@
**[Mouse modifiers](mouse_modifiers)** — what Shift, Ctrl and Alt change while you drag
**[Aligning items](aligning_items)** — snap symbols back to the grid *(pending)*
**[3D mouse](3d_mouse)** — SpaceMouse pan, zoom and buttons
**[Aligning items](aligning_items)** — snap symbols back to the grid
**[Pictures on a folio](pictures)** — labels, crop, transparency, what they cost in the file
**[Grouping items](grouping_items)** — select, move and copy several items as one *(pending)*
-6
@@ -34,12 +34,6 @@ translations are updated, with an English gloss in italics.
## Snap to grid
> **Status: pending.** This section describes
> [PR #1073](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1073),
> not yet merged. Nothing here works until that lands — check the PR before
> trying any of this against your own build. This section will drop this
> notice once it does.
### Using it
1. Select the items to fix. **Ctrl+A** selects everything on the folio,
+26 -6
@@ -203,13 +203,33 @@ automatically. The drawing looks fine; the hand-routing is lost.
## 7. Colouring quickly
Select exactly one conductor and press **F2** to open a colour picker for it.
The shortcut does nothing with several conductors selected, or none.
The **Couleur de conducteur** (*Conductor colour*) swatch on the **Schéma**
toolbar colours every selected conductor in one click:
> A toolbar colour button that applies to every selected conductor at once, and
> sets the colour of the next conductor drawn, is proposed in
> [PR #929](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/929).
> Until it merges, F2 one at a time — or Search & Replace for bulk changes.
1. Select the conductors: one, several, or **Ctrl+A** for the whole folio.
2. Open the swatch and pick a colour.
The menu lists the colours electricians name — Noir, Marron, Gris, Bleu,
Vert, Rouge, Orange, Violet, Blanc (*black, brown, grey, blue, green, red,
orange, violet, white*) — then the custom colours you picked this session under
*Récemment utilisées*, then **Autre couleur…** for the full colour dialog.
What it does:
- **Whole wires, not segments.** A wire split into several segments by
junctions is recoloured along its whole electrical potential, as the
properties dialog does.
- **One undo step** for the whole selection.
- **The next wire too.** The picked colour becomes the colour of the next
conductor you draw. With nothing selected, picking a colour only does that.
- **Nothing is saved as a setting.** The colour lives on the conductors it was
applied to; the recent list is forgotten when QET closes.
The swatch is greyed out when no folio is open or the project is read-only.
**F2** still opens the colour picker for exactly one selected conductor, and
does nothing with several selected or none. For bulk changes across folios by
some other criterion, use **[Search & Replace](search_and_replace)**.
There are **no named conductor presets**. A project has a single default set of
conductor properties, not a library of named ones; the request for that is
+6
@@ -31,3 +31,9 @@ Connections:
Order matters: parts are drawn in document order, so a later sibling paints over
an earlier one.
Every part may carry a `uuid` attribute, its permanent id within the symbol.
Terminals and dynamic texts have long had one. Since September 2026 the element
editor also writes one on every shape and fixed text when it saves, and paste
in the editor gives the copies new ids. Symbols without them load normally,
and older versions of QElectroTech ignore the attribute on shapes and texts.
+13 -3
@@ -7,12 +7,22 @@ attribute : none
## child elements
* `<image>`, with attributes:
* uuid -- the picture's permanent id
* x, y, z -- position and stacking order
* size -- scale factor
* rotation -- degrees
* is_movable -- `true` / `false`
* is_movable -- `1` / `0`
* label -- caption drawn under the picture; written only when set
The image data itself is stored base64-encoded as the text node of the
`<image>` element, so a project file stays self-contained.
The image data itself is stored as PNG, base64-encoded, as the first text node
of the `<image>` element, so a project file stays self-contained.
Optional children, each written only when it carries something:
* `<transform>` -- rotation, skewX, skewY, scaleX, scaleY, pivotX, pivotY
* `<transparent_colors>` -- one `<color r g b tolerance>` per keyed colour
* `<crop>` -- x, y, w, h of the kept region
* `<image_base>` -- the untouched original, PNG base64, when cropped or keyed
See **[Pictures on a folio](pictures)** for what each does.
Written only when the folio has at least one image, by `Diagram::toXml()`.
+1
@@ -8,6 +8,7 @@ attribute : none
## child elements
* `<input>`, with attributes:
* uuid -- the text's permanent id
* x, y -- position
* text -- the string
* font -- serialised `QFont`
+2 -1
@@ -8,12 +8,13 @@ attribute : none
## child elements
* `<shape>`, with attributes:
* uuid -- the shape's permanent id
* type -- `Line`, `Rectangle`, `Ellipse` or `Polygon`
* x1, y1, x2, y2 -- defining points
* rx, ry -- corner radii, for rectangles
* closed -- for polygons
* z -- stacking order
* is_movable -- `true` / `false`
* is_movable -- `1` / `0`
These are diagram shapes and are **not** the same as the element drawing
primitives documented under [description](elements_child_description), even
+37 -2
@@ -92,9 +92,11 @@ A master can describe the contacts it actually offers, typed and labelled:
<kindInformations>
<kindInformation name="type">coil</kindInformation>
<slaveContactGroups>
<group type="NO" subtype="simple" contactCount="2" terminalCount="2">
<group type="NO" subtype="simple" contactCount="2" terminalCount="4">
<label>13</label>
<label>14</label>
<label>23</label>
<label>24</label>
</group>
<group type="NC" subtype="simple" contactCount="1" terminalCount="2">
<label>21</label>
@@ -109,13 +111,46 @@ A master can describe the contacts it actually offers, typed and labelled:
| `type` | `NO`, `NC`, `SW`, `Other` | Contact state. Defaults to `NO`. |
| `subtype` | `simple`, `power`, `delayOn`, `delayOff`, `delayOnOff`, `plc` | Contact kind. Defaults to `simple`. |
| `contactCount` | integer | How many contacts this group provides. Defaults to `1`. |
| `terminalCount` | integer | Terminals per contact. Defaults to `1`. |
| `terminalCount` | integer | Terminals in the whole group, shared out over its contacts in order. Defaults to `1`. |
| `<label>` | text | One per terminal, in order (`13`, `14`, …). |
The whole block is written only when the *Contact groups* checkbox is ticked in
the editor; when it is present on load, that checkbox is ticked again. It is not
available for `plc` masters.
In the element editor, changing a group's contact count changes its terminal
count with it, keeping the same number of terminals per contact (2 by default,
3 for a changeover `SW`). A terminal count you type yourself stands until you
change the contact count again.
### Showing every declared contact in the comb
By default a master's contact comb (the cross-reference drawn as contacts under
a coil) shows only the slaves actually linked to it, in their order on the
folios. When the master declares contact groups, it can show **all** of them
instead, before any slave is placed, so you can see which contacts are still
free.
Turn it on in the **Cross-references** tab (*Références croisées*) of a
project's properties, or of *Preferences ▸ New project* for future projects
(see **[Preferences reference](preferences)** §2). Pick the element type, keep
**Afficher en contacts** (*Show as contacts*) selected, and tick **Afficher tous
les esclaves définis par le maître** (*Show all slaves defined by the master*).
The checkbox is greyed out while *Afficher en croix* (*Show as cross*) is
selected, and hidden for PLC masters, which always draw their I/O table.
With it on:
| Slot | Drawn as |
|---|---|
| Linked to a slave | as before: the slave's position, hover and double-click to jump to it |
| Free | the contact symbol and the terminal numbers from the group, with no position and no hover or double-click |
| A linked slave with no group assigned | added after the declared groups, in folio order |
A master that declares no contact groups draws exactly as before, with or
without the option. It is saved in the project as the `showallconfiguredslaves`
attribute; a project without it has the option off.
**Status: shipped but unused.** Of the 6 918 elements in the `10_electric`
collection, **0** declare `slaveContactGroups` and **0** declare `max_slaves`.
The feature works, but no element in the shipped collection exercises it yet, so
+11 -11
@@ -19,7 +19,7 @@ Source: `sources/diagram.cpp`, `sources/diagram.h`, `sources/editor/elementscene
The folio grid is a set of dots at regular intervals, purely for visual
alignment and mouse-snap — it carries no unit of measurement (not mm, not
inches). Six settings control it, all under `QSettings` key prefix
inches). Seven settings control it, all under `QSettings` key prefix
`diagrameditor/`:
| Setting | QSettings key | Default | Controls |
@@ -30,8 +30,9 @@ inches). Six settings control it, all under `QSettings` key prefix
| Y keyboard-nudge step | `key_Ygrid` | 10 | how far ↑ and ↓ move a selection |
| X fine-nudge step | `key_fine_Xgrid` | 1 | → / ← step while the fine-movement modifier is held |
| Y fine-nudge step | `key_fine_Ygrid` | 1 | ↑ / ↓ step while the fine-movement modifier is held |
| Text grid | `text_grid_divisor` | 1 | dragged texts snap to the grid divided by this: 1, 2, 5 or 10; 0 turns the snap off |
All six are exposed on the General page of *Edit → Preferences* (see
All seven are exposed on the General page of *Edit → Preferences* (see
**[Preferences reference](preferences)** §1, "Grid and keyboard movement").
The in-app spin boxes cap X/Y grid spacing at 1–30; there is no upper cap in
the underlying setting itself, only in that dialog.
@@ -42,14 +43,13 @@ the two values as you zoom in from 100% up to 500% (`Diagram::drawGrid()`).
This is purely cosmetic: it does not change spacing or snap behaviour, only
how visible the dots are at a given zoom level.
**Mouse-drag movement always snaps to `Xgrid`/`Ygrid`**, independent of the
keyboard-nudge settings above; Ctrl while dragging bypasses the snap. See
**[Mouse modifiers](mouse_modifiers)** for the full modifier table. One
exception is tracked as a bug: dragging a *dynamic element text* (the text
attached to an element, under the cursor) does not snap at all, unlike every
other draggable text or item — reported upstream as
[issue #923](https://github.com/qelectrotech/qelectrotech-source-mirror/issues/923).
If a device label refuses to land on the grid after a drag, this is why.
**Mouse-drag movement snaps to `Xgrid`/`Ygrid`**, independent of the
keyboard-nudge settings above; Ctrl while dragging bypasses the snap. Texts
are the exception: they snap to the *text grid*, the folio grid divided by
`text_grid_divisor`, so a label can sit between two grid points and still
line up with the labels of other symbols. The default of 1 is the folio grid
itself. See **[Mouse modifiers](mouse_modifiers)** §2 for where to change it
and for the full modifier table.
## 2. Element size: how the element editor enforces the grid
@@ -120,5 +120,5 @@ against neighbouring symbols and resize by hand if it needs to match.
- **[Preferences reference](preferences)** — where the grid settings live in the UI
- **[Using the element editor](element_editor)** — drawing tools, saving, checks
- **[Mouse modifiers](mouse_modifiers)** — Shift/Ctrl/Alt while dragging
- **[Aligning items](aligning_items)** — putting symbols that left the grid back on it *(pending)*
- **[Aligning items](aligning_items)** — putting symbols that left the grid back on it
- **[Elements XML](elements_XML)** — the `<definition>` `width`/`height`/`hotspot` attributes
+2
@@ -281,6 +281,8 @@ roadmap.
- **[Mouse modifiers](mouse_modifiers)** — the other half: what Shift,
Ctrl and Alt change while you drag with a mouse
- **[3D mouse](3d_mouse)** — binding a SpaceMouse's buttons to these same
commands
- **[Preferences reference](preferences)** — the Shortcuts page (§4) and
the grid/keyboard-nudge settings (§1) referenced above.
- **[Tips & Tricks](tips_and_tricks)** — general workflow tips, including
+33 -11
@@ -39,20 +39,40 @@ Two things follow that are easy to trip over:
| You drag | Plain | With a modifier |
|---|---|---|
| An element, image or shape | snaps to the grid | **Ctrl** — fine positioning |
| A free text field | snaps to the grid | **Ctrl** — fine positioning |
| A conductor's text | snaps to the grid | **Ctrl** — fine positioning |
| **An element's own text** (label, reference, information field) | moves **the whole element** | **Shift** — moves the text alone, leaving the element where it is |
| A group of element texts | snaps to the grid | **Ctrl** — fine positioning |
| A free text field | snaps to the text grid | **Ctrl** — fine positioning |
| A conductor's text | snaps to the text grid | **Ctrl** — fine positioning |
| **An element's own text** (label, reference, information field) | moves **the whole element** | **Shift** — moves the text alone, snapped to the text grid; release Shift and hold **Ctrl** for fine positioning |
| A group of element texts | snaps to the text grid | **Ctrl** — fine positioning |
The Shift row is the one people ask about. Clicking an element's label and
dragging moves the element, because the label hands the event to its parent.
Hold **Shift** as you press, and the label moves on its own.
> **Note.** An element's text is the one thing on the folio that does not snap
> to the grid when you drag it — it moves in single units instead. That is
> being changed in
> [PR #927](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/927);
> until it is merged, expect labels to land off-grid.
While you drag an element's text, the status bar names the text grid in use
and repeats the hint: *release Shift, hold Ctrl to place freely*. Ctrl and
Shift together are reserved by the folio view (§1).
### The text grid
Texts do not have to snap to the full folio grid. **Affichage ▸ Grille des
textes** (*View ▸ Text grid*), the **Textes 1:1** button on the **Affichage**
(*View*) toolbar, and *Preferences ▸ General ▸ Grille + Clavier* all set the same
choice:
| Choice | A dragged text snaps to |
|---|---|
| **1:1** (default) | the folio grid, as symbols do |
| **1:2**, **1:5**, **1:10** | a half, a fifth or a tenth of a grid step |
| **Désactivée** (*Off*) | the nearest unit, as with Ctrl |
Every step divides the folio grid exactly, so texts on different symbols still
line up with each other. The choice is a preference of your installation, not
of the project: nothing in a saved file changes. The finer grid is not drawn on
the folio.
Before September 2026 an element's own text did not snap at all, so most labels
in older projects sit off the grid. The first drag of such a label pulls it
onto the text grid, by at most half a step.
---
@@ -121,7 +141,7 @@ separately from the grid the mouse snaps to.
A few **Alt**+arrow presses leave a symbol between grid points, which bends
its wires. **[Aligning items](aligning_items)** describes the command that
puts it back *(pending, PR #1073)*.
puts it back.
---
@@ -179,6 +199,8 @@ rotating. It keeps its own grid settings, separate from the diagram's.
- **[Keyboard-only control](keyboard_control)** — driving QET without a mouse
- **[Preferences reference](preferences)** — the grid and movement settings
- **[Templates](templates)** — which are placed by dragging, and nothing else
- **[Aligning items](aligning_items)** — snap a selection back to the grid *(pending)*
- **[Aligning items](aligning_items)** — snap a selection back to the grid
- **[Grouping items](grouping_items)** — select and move several items as one *(pending)*
- **[Pictures on a folio](pictures)** — the handles for resizing, rotating and skewing a picture
- **[3D mouse](3d_mouse)** — panning and zooming with a SpaceMouse
- **[Tips & Tricks](tips_and_tricks)** — faster drawing generally
+1
@@ -176,3 +176,4 @@ Like the bars, the lines are part of the view, not the drawing: they are
- **[Keyboard-only control](keyboard_control)** — every other shortcut,
including Ctrl+G for elements
- **[Preferences reference](preferences)** — the other settings pages
- **[3D mouse](3d_mouse)** — panning and zooming around a folio with a SpaceMouse
+142
@@ -0,0 +1,142 @@
# Pictures on a folio
A folio can carry pictures alongside the drawing: a photo of the cabinet, a
supplier's logo, a screenshot of an HMI page. QElectroTech copies the picture
**into the project file**, so the project stays complete when it is moved or
sent on; nothing points back to the file you picked.
This page covers inserting a picture, the handles, the properties panel, the
picture's own right-click menu, and what it costs in the saved file.
---
## 1. Inserting a picture
1. Click **Ajouter une image** (*Add a picture*) on the **Ajouter** (*Add*)
toolbar.
2. Pick a file: PNG, JPEG, BMP or SVG.
3. Click on the folio where the picture should go.
A picture is an ordinary folio item: it moves, copies, pastes, snaps to the
folio grid and undoes like everything else.
---
## 2. Resizing, rotating and skewing with the handles
A selected picture shows handles, in one of two modes. **Click the selected
picture** to switch between them; the tooltip names the mode the next click
gives.
| Mode | Drag | Modifier |
|---|---|---|
| **Resize** | a corner or an edge | **Shift** keeps the proportions, **Ctrl** resizes from the centre |
| **Rotate / skew** | a corner to rotate, an edge to skew | **Shift** snaps to 15° steps |
| **Rotate / skew** | the red dot | moves the centre of rotation |
While the pointer is over a selected picture, the status bar lists the same
gestures for the current mode.
---
## 3. The properties panel
Select a picture and the **Propriétés de la sélection** (*Selection
properties*) panel shows:
| Field | Does |
|---|---|
| **Largeur** / **Hauteur** (*Width* / *Height*) | size as a percentage of the source image. The lock between them keeps the proportions; click it to size each on its own |
| **Restaurer les proportions** | makes the height percentage match the width again, undoing a stretch |
| **Angle** | rotation, in degrees |
| **Inclinaison X** / **Inclinaison Y** (*Skew X / Y*) | skew, in degrees |
| **Libellé** (*Label*) | a caption under the picture — see below |
| **Verrouiller la position** (*Lock position*) | stops the picture from being moved |
### The label
Text typed in **Libellé** is drawn centred under the picture. It belongs to
the picture: it moves, copies, rotates and prints with it, and clicking the
label selects the picture. It stays at normal folio text size however large or
small the picture is scaled, using the font set for folio texts in the
preferences. Leave the field empty to remove the label.
Before the label existed, the only way to caption a picture was a separate free
text, which had to be selected together with the picture every time either was
moved.
There is no per-label font, colour or position.
---
## 4. The right-click menu
Right-click a picture for its own commands, above the usual folio ones:
| Command | Does |
|---|---|
| **Remplacer l'image…** (*Replace picture*) | swaps in another file, keeping position, scale and rotation; any crop or transparent colours are cleared |
| **Enregistrer l'image sous…** (*Save picture as*) | writes the picture as it looks on the folio, crop and transparency applied, to PNG, JPEG, BMP or SVG |
| **Enregistrer l'image d'origine sous…** (*Save original picture as*) | writes the picture as it was inserted, before any crop or transparency |
| **Couleur transparente…** (*Transparent colour*) | picks one or more colours to make see-through, each with a tolerance — for a logo on a white background, say |
| **Rogner…** (*Crop*) | keeps only a rectangle of the picture |
| **Miroir horizontal** / **Miroir vertical** | flips the picture |
| **Restaurer les proportions** | as in the properties panel |
Crop and transparency do not destroy the original: it stays in the project, so
either can be changed again later, and **Enregistrer l'image d'origine sous…**
gets it back. JPEG and BMP cannot hold transparency; QElectroTech warns before
saving a see-through picture to one of them.
---
## 5. In the project file
Each picture is an `<image>` element in its folio's `<images>` block (see
**[Project XML](project_diagram_child_images)**):
| Part | Holds |
|---|---|
| text content | the picture as displayed, PNG, base64-encoded |
| `x`, `y`, `z` | position and stacking order |
| `rotation`, `size` | angle and scale, as older versions read them |
| `is_movable` | `0` when the position is locked |
| `uuid` | the picture's permanent id |
| `label` | the label, only when one is set |
| `<transform>` | separate X/Y scale, skew and rotation centre, only when needed |
| `<crop>`, `<transparent_colors>` | the crop rectangle and keyed colours, only when used |
| `<image_base>` | the untouched original, only when the picture is cropped or keyed |
Things that follow from this:
- **Pictures are always stored as PNG.** A JPEG photo becomes a PNG inside the
project, which is often several times larger than the JPEG was. Scale a large
photo down before inserting it if file size matters.
- **A cropped or keyed picture is stored twice**, displayed and original.
- **Older versions open these projects.** They read the picture, position,
rotation and scale, and ignore the label, the uuid and the rest; saving from
an older version drops them.
- **Saving is quick even with many pictures.** Each picture's PNG is encoded
once and reused on every later save until the picture changes.
A picture also appears in the project database's `image` table and in
`drawing_item_view` — see **[The project database](project_database)**.
---
## 6. Limitations
| Limitation | Detail |
|---|---|
| DXF export | pictures become outline boxes: see **[DXF import & export](dxf)** |
| Label styling | the label uses the folio text font; no per-label font, colour or position |
| No link to the source file | changing the file on disk does not update the project; use **Remplacer l'image…** |
---
## See also
- **[Mouse modifiers](mouse_modifiers)** — Shift, Ctrl and Alt while dragging
- **[Aligning items](aligning_items)** — putting pictures back on the grid
- **[Printing and exporting](printing_and_export)** — what reaches paper and PDF
- **[The project database](project_database)** — the `image` table
+20 -1
@@ -73,6 +73,9 @@ everything else, respectively.
- Grid spacing (1–30)
- Keyboard-nudge step (1–30) — how far arrow keys move a selection
- Keyboard-nudge step with **Alt** held (1–9) — the fine-movement modifier
- *Grille des textes déplacés à la souris* (text grid for dragged texts): 1:1,
1:2, 1:5, 1:10 of the folio grid, or off — see
**[Mouse modifiers](mouse_modifiers)** §2
---
@@ -152,6 +155,14 @@ action already uses a key you're about to reassign.
---
## 4b. Souris 3D (3D mouse)
Only in builds with 3D mouse support: pan and zoom speed, zoom by push/pull or
twist, dead zone, inverting each direction, and binding the device's buttons
to commands. See **[3D mouse](3d_mouse)**.
---
## 5. What's notably *not* here
- **No per-diagram auto-save interval.** QET writes a periodic
@@ -162,9 +173,17 @@ action already uses a key you're about to reassign.
layout.
- **No dark-mode toggle distinct from "use system colours."** Theme follows
the OS unless you opt out of that.
- **The folio background colour is not on any page.** It is the **Couleur de
fond du folio** (*Folio background colour*) button on the **Affichage**
(*View*) toolbar: *Couleur système* (follow the system theme, dark on a dark
desktop), a list of fixed colours, recent choices, or *Autre couleur…*. It
applies to every open project and, since September 2026, is remembered
between runs, recent choices included. It is kept in your settings, not in
the project. See **[Printing and exporting](printing_and_export)** §4 for
what it does to output.
---
See also: **[Project XML](project_XML)** · **[Linking elements](element_linking)** ·
**[Linking wires across pages](folio_links)** · **[DXF import & export](dxf)** ·
**[Grid size and element size](grid_and_element_size)**
**[Grid size and element size](grid_and_element_size)** · **[3D mouse](3d_mouse)**
+4
@@ -129,6 +129,10 @@ documents folder, and falls back to it if the saved folder no longer exists.
- **Print settings and image-export settings are separate.** Setting up one
does not set up the other.
- **SVG transparency only applies to SVG.** Ticking it for a PNG does nothing.
- **The folio background colour is screen-only for printing.** The background
chosen with the *Couleur de fond du folio* button on the *Affichage* toolbar
is used by **File → Export to images**, which exports what you see, but
printing and PDF always use white, and so do command-line exports.
---
+46 -7
@@ -31,6 +31,7 @@ queries, and uses it for the things that are naturally queries:
| `--export-bom` (CLI) | `element_nomenclature_view` |
| `--export-wires`, `--export-cables` (CLI) | `wiring_list_view` |
| Folio summary tables | `project_summary_view` |
| Scripting's `qet.query()` | any table or view |
None of these are storage. Every one of them is a *report* about data that
already exists in the XML.
@@ -43,14 +44,15 @@ already exists in the XML.
QETProject constructed
└── projectDataBase constructed → createDataBase()
├── open an anonymous SQLite connection
├── CREATE TABLE × 6, CREATE VIEW × 3
├── CREATE TABLE × 9, CREATE VIEW × 4
└── updateDB()
project XML read
└── updateDB() ← full repopulate, once, after everything is loaded
user edits the diagram
└── addElement / removeElement / elementInfoChanged
addDiagram / removeDiagram / diagramInfoChanged / diagramOrderChanged
addConductor/ removeConductor / updateConductor ← incremental
addConductor/ removeConductor / updateConductor
drawingItemChanged / drawingItemDestroyed ← incremental
project closed
└── database discarded
```
@@ -73,7 +75,7 @@ the console output rather than guessed at.
## 3. Schema
Six tables:
Nine tables:
| Table | Key | Notes |
|---|---|---|
@@ -83,9 +85,23 @@ Six tables:
| `element_info` | `element_uuid` | one column per `QETInformation::elementInfoKeys()` — 57 today |
| `terminal` | **(`uuid`, `element_uuid`)** | see §4 |
| `conductor` | `uuid` | both endpoints as (terminal uuid, element uuid) pairs |
| `shape` | `uuid` | lines, rectangles, ellipses, polygons: `type`, `color`, `fill` |
| `independent_text` | `uuid` | free texts on a folio: `text`, `rotation` |
| `image` | `uuid` | pictures: `pixel_width`, `pixel_height` of the source image |
Three views: `element_nomenclature_view`, `project_summary_view`,
`wiring_list_view`.
The last three share their first columns: `uuid`, `diagram_uuid`, `pos` (the
folio cell of the item's top-left corner, as for `element`), and `x`, `y`,
`width`, `height`, the item's bounding box on the folio. They follow edits as
they happen, like the element and conductor tables.
Four views: `element_nomenclature_view`, `project_summary_view`,
`wiring_list_view`, and `drawing_item_view`, which lists shapes, texts and
pictures together with a `kind` column (`shape`, `text`, `image`) and the
folio's position in the project as `folio`:
```sql
SELECT kind, folio, pos, description FROM drawing_item_view ORDER BY folio, pos;
```
Note what the column lists mean: **the schema is generated from
`elementInfoKeys()` at runtime.** Adding an element information field adds a
@@ -107,12 +123,35 @@ instance — silently lost every conductor that ended on a relay contact. A
nomenclature's opinion about what counts as a line item does not belong in the
project's model of itself.
### Queries are read-only
The SQL box of a nomenclature table, queries saved in a project and
scripting's `qet.query()` run with SQLite's `query_only` setting on, so a
statement that would write (`INSERT`, `UPDATE`, `DROP`…) is refused.
Development builds from 26–27 September 2026, between
[PR #1046](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1046)
and its fix in
[PR #1066](https://github.com/qelectrotech/qelectrotech-source-mirror/pull/1066),
had a side effect: a query whose rows came back unsorted — a `UNION ALL`
without `ORDER BY`, as `drawing_item_view` is — returned only its **first
row**, with no error. If such a build gives you one row where you expect many,
add an `ORDER BY`.
---
## 4. Identity, and why terminals are hard
Rows need stable keys. Elements and diagrams have real UUIDs, so they are fine.
Terminals are not.
Rows need stable keys. Elements, diagrams and conductors have real UUIDs, so
they are fine. Since September 2026 so do shapes, free texts and pictures on a
folio, and the parts drawn inside a symbol: each carries a `uuid` attribute in
the saved file. An item from a file saved before then gets one worked out from
its folio, its kind and its order in the file, so opening the same file twice
gives the same ids. Paste and folio duplication give the copies new ids.
Older versions of QElectroTech open such files and drop the attribute when they
save.
Terminals are not so lucky.
`Terminal::uuid()` comes from the catalogue `.elmt` definition. It identifies
*a terminal position in a symbol* — "the top terminal of a contactor" — and is
+9
@@ -357,6 +357,15 @@ For **Wires:**
### Bills of Materials & Parts Lists
**Keep spellings consistent:** a parts list or query compares exact text, so
"Schneider" and "Schneider Electric" end up as two suppliers. When you fill in
an element's **Informations** tab (manufacturer, supplier, reference…), each
field suggests the values other elements of the same project already use.
Matching ignores case and works anywhere in the text — typing "ard" offers
"Arduino" — so pick the existing spelling instead of typing a new one. The
*Label* field has no suggestions, since a label names one element; nor do
values from other projects.
**Generate Automatically:**
1. **Projet → Exporter au format CSV**
2. Creates element count and reference list