Development Strip Editor - ShadobaDev/Platemaker-qt GitHub Wiki

Strip editor β€” the tool framework

How the strip editor is put together: what a tool is, what an object is, and which panel is allowed to talk about which. To add a tool, a shape or a kind of object, the file-by-file recipes are in Extending the strip editor in the repository; this page is the why behind them. Where each part lives in the code is the code map.

Status β€” built. The property groups and their editors, the tool registry, both panels, the preset store, one history per project, advisories, multi-selection with roles, and the object stack as a tree whose rows include the strip, its pages and a bubble's tails.

Why there is a framework at all

The symptom was cosmetic: the editor showed what looked like the same panel twice, once under the tool rail and once on the right. The cause was not.

Objects in this editor are a type hierarchy. Tools are an enum and six if statements in one function, so a tool has nowhere to keep what it is about to make. The only class able to hold that state was the properties panel, so the panel was instantiated twice β€” once bound to the selection, once standing in as the tool's memory β€” and told apart by an enum naming which panel it was sitting in.

A widget that knows which panel it is in is a layering violation, and this one produced two identical panels. The framework exists to give the tool somewhere to live, so the panel does not have to be it.

Vocabulary

These five words are used precisely throughout this section.

Noun Identity Example
Object a uid at top level, a local handle when nested a bubble, imported artwork, the strip, a page, a tail
Property none β€” a field fill, fontPixelSize, bend
Property group a name and a struct SkinProperties, TextProperties, TailProperties
Role a name, matched across kinds position, text colour, typeface
Tool one rail entry; stateless, so it is a row in a table rather than a class Select, Pan, Colour correction, Bucket paint, Colour picker, Speech bubble, Artwork, Text
Mode none β€” a state, not an entry the default select/move state; view panning
Advisory a key β€œ3 objects unanchored”

There is no separate type for a nested object. A tail is an Object whose parent is a bubble; a page is an Object whose parent is the strip. Nesting is a position in the tree, not a kind of thing.

What separates a nested object from a property group is one test: can there be several of it, and can one be deleted? A tail can, so a tail is selected and deleted on its own. A fill colour cannot. A bubble's text cannot either: there is exactly one, and it can be emptied but not removed, so it is a group.

Tools are stateless; objects carry state. A tool that appears to remember something β€” the preset it will apply, the primary colour β€” is holding a reference to something stored elsewhere: the preset library, or the application's colour pair.

Layers

Five concerns, and one rule that keeps them apart.

Layer Owns May know about
L0 Object model objects, nesting, identity, z-order the library's models; no widgets
L1 Property model groups, roles, field ownership, applyTo L0; no widgets
L2 Property editors one widget per group L1 and Qt; not which panel it is in
L3 Tool framework the registry, activation, canvas input routing L0–L2
L4 Surfaces which region hosts which editor, bound to which subject L2, L3
L5 History commands, the undo stack L0, L1

Arrows point down. The layering violation that produced the duplicated panel was an L2 widget carrying an enum describing its L4 position. If an editor must look different in one region, the region asks it to be compact; the editor does not ask where it is.

L1 stays free of QWidget for a second reason: it makes the ownership tests plain console tests. See Property groups.

The regions

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  TOP BAR β€” document & view: seams, zoom, fit, render preview, undo       β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ TOOL RAIL     β”‚                                  β”‚ OBJECT STATE          β”‚
β”‚ β–£ β–£ β–£ β–£     β”‚                                  β”‚  bubble#7             β”‚
β”‚ β–£ β–£          β”‚          CANVAS                  β”‚  β–Έ Placement          β”‚
β”‚ β– /β–‘ colours   β”‚                                  β”‚  β–Ύ Skin      [Shout]  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€    selection chrome, handles,    β”‚     [fill] [stroke]   β”‚
β”‚ TOOL OPTIONS  β”‚    placement ghost               β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  preset β–Ύ     β”‚                                  β”‚ OBJECT STACK (tree)   β”‚
β”‚  [the groups  β”‚                                  β”‚  β–Έ πŸ—¨ "Text…"         β”‚
β”‚   it fills]   β”‚                                  β”‚  β–ͺ logo.svg           β”‚
β”‚               β”‚                                  β”‚  β–Έ β–¬ STRIP            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ ready.                    (β›” 3 objects unanchored) (⚠ 2 fonts missing) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Region Subject Empty when Code
Top bar the document and the view never editor.ui
Tool rail β€” never toolrail/
Canvas the strip never canvas/, and what is on it in objects/
Object state the selection nothing selected, or the selection has nothing in common objectstate/
Tool options the active tool's options the tool has none tooloptions/
Object stack the document never β€” the strip is always there objectstack/
Status bar the document nothing to report the main window's

The folders are under widgets/stripeditor/; the code map lists their files and what each may include.

Three rules follow, and they are the whole answer to the duplicated panel:

  • OBJECT STATE and TOOL OPTIONS may use the same editor class, never the same instance, and never the same subject. TOOL OPTIONS is bound to what the tool will make; OBJECT STATE is bound to what is selected.
  • OBJECT STATE belongs to the selected object, whichever tool is active. Selecting a tool that authors nothing does not empty it and does not hide it. Hiding it resizes the canvas, which makes the strip jump sideways when the tool changes; that was fixed on 2026-09-12 and must not come back.
  • TOOL OPTIONS belongs to the active tool. "What the next object will be" is the most common kind of tool option, not the only kind β€” a transform tool's snapping settings live there too.

Where a tool becomes visible

A tool has two faces. The colour tool is the clearest case: in OBJECT STATE it edits the selection's fill and stroke; on the rail it carries the application's colour pair and applies it to whatever you click. One tool, one property group, two bindings.

Surface A tool contributes A property group contributes An object contributes
Tool rail its icon, always β€” β€”
Tool options its options page while active the groups a preset fills, and the preset badge β€”
Object state its editor face, bound to the selection its section which groups exist; the breadcrumb
Object stack β€” reporting badges (blend, unanchored, preset) a row each, nested
Canvas placement ghost, rubber band, cursor β€” selection chrome, handles
Status bar advisories it raises β€” advisories about it
Context menu tool actions, Convert to β–Έ, Re-anchor to β–Έ apply this group delete, reorder

Selection

Selection is a set of paths β€” strip/bubble#7/tail#2 β€” shown in three places at once and always agreeing: the tree row, the canvas chrome, and a breadcrumb at the top of OBJECT STATE. With several objects selected the breadcrumb reads 3 objects and hovering lists them.

Canvas clicks select outermost first: click a bubble and you get the bubble; click again, or click a tail handle, and you get the tail.

Selection belongs to the canvas, not to a tool. Every object is selectable, movable and resizable under every tool β€” a tool decides what a placement creates, never whether what is already there can be touched. The one exception is an unanchored object, which is not on the strip and so has nothing to be selected on.

Nested objects carry a GUI-local handle, never a workspace uid β€” uids belong to the library and a tail is not independently addressable there. A tail's handle is its index (Q60). Deleting tail 0 renumbers tail 1, but nothing is left holding "tail 1": undo restores whole states, and a selection whose bubble changes its number of tails moves up to the bubble.

Pages in this section

Page Covers
Code map Which folder holds which region, what may include what, how the parts talk
Property groups The structs, ownership, roles, the write contract, the tests
Object state and tool options What OBJECT STATE, TOOL OPTIONS and OBJECT STACK contain, presets and their badge
History and undo One history per project, typed steps, dock attention
Advisories and badges The registry, the status bar, widgets/badge/
Inputs and anchoring Replacing a page, unanchored objects, the render gate

See also: Architecture Β· Contributing Β· Rendering