gfx/component_builder.h
ComponentBuilder: a component tree built from a data tree, and kept in step with it.
#include <sonore/gfx/component_builder.h>- 1type
- Guides: The native editor
On this page
Design notes
What it is for
An interface described as DATA -- a layout a designer edits, a skin loaded with a preset, a panel a plugin assembles from what the user configured -- has to become components, and has to stay right when the data changes. The second half is the hard half: rebuilding the whole tree on every edit loses focus, hover, scroll positions and every animation in flight, and a user typing in a field that was rebuilt under them loses their text. So the builder RECONCILES: a node whose id and type are unchanged keeps its component and is only told its new state; a new node gets a new component; a node that has gone takes its component with it; the order of children is made to match.
The data
A JsonValue object per component, json.h's tree being the SDK's data tree:
{ "type": "Panel", "id": "main", "bounds": [0, 0, 400, 300],
"children": [ { "type": "Knob", "id": "gain", ... }, ... ] }
type- chooses the TypeHandler that makes and updates it -- required
id- how a node is matched across edits (Component::componentID); a node with none is matched by its position among the id-less siblings of its type
bounds- optional: [x, y, w, h], or a RelativeRectangle string -- "parent.width - 110, 10, parent.width - 10, 40" -- which is applied as a live relative position
children- optional: the nodes inside it, in z-order
Everything else is the handler's to read. JsonValue is a VALUE -- there is no listener on it to tell the builder what changed -- so a change is a new tree handed to setState(), and the diff above is how only the changed parts are touched.
The builder OWNS what it builds; Component itself does not own its children, and the tree here is the one place that decides their lifetime.
Types 1
Builds a component tree from a JsonValue tree, and reconciles it when a new tree is handed over. The reference's class of the same name, over json.h's tree instead of its own; the file comment gives the node format and how a node is matched across edits.
Register a TypeHandler for every "type" first. getManagedComponent() builds the tree on its first call, and setState() brings it up to date after that. The builder OWNS every component it makes: a pointer from getManagedComponent() or findComponentByID() dies with the builder, and with the node -- a setState() that drops a node, or changes its type, destroys its component. Message thread only.