mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-31 13:56:54 -06:00
M3: reorder paints, effects and layout grids in the Design panel; grid and instance property variable bindings (#81)
Fill, stroke, effect and layout grid rows drag to reorder by their grip (a handle shows over the
row, an insertion line where it lands, the row's label follows the pointer like a dragged layer;
Escape cancels; lists that differ across the selection have nothing to drag). New commands
`fill.move`, `stroke.move` and `grid.move {ids?, from, to}` join `effect.move` (lists bottom first,
one undo step; items keep everything, linked list styles are unlinked).
Variable bindings on list items follow their items when a list is reordered or shrinks:
paint colours bind per paint (`fills/<i>/color`, `strokes/<i>/color`; `fill`/`stroke` stay the
first paint's), so a moved bound paint keeps its variable and its neighbours are never recoloured.
`fill.remove`, `stroke.remove` and `grid.remove` refuse negative indices.
Layout grids get settings in the Design panel (size; count, type, width or height, margin or
offset, gutter; colour) whose numbers bind to number variables (`layoutGrids/<i>/<field>`),
re-applied on variable and mode changes. Instance boolean and text properties bind to boolean and
string variables (`componentProperties/<name>`, from the instance's properties panel), kept across
instance rebuilds, following property renames and dropped on delete, reset and detach.
Inspect names the variable of each paint.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -344,6 +344,7 @@ fn carry_overrides(from: &Node, to: &mut Node, what: Carry) {
|
||||
if let (NodeKind::Instance { props: a, .. }, NodeKind::Instance { props: b, .. }) = (&from.kind, &mut to.kind) {
|
||||
*b = a.clone();
|
||||
}
|
||||
carry_prop_bindings(from, to);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -382,6 +383,18 @@ fn path_map(doc: &Document, root: NodeId, src_names: bool) -> BTreeMap<NodeId, S
|
||||
out
|
||||
}
|
||||
|
||||
/// The binding key prefix of an instance's component property value
|
||||
/// (`componentProperties/<name>`): a boolean property takes a boolean variable, a text property a
|
||||
/// string variable.
|
||||
pub const PROP_BINDING: &str = "componentProperties/";
|
||||
|
||||
/// Give `to` the component property bindings of instance `from` (they go with its property
|
||||
/// values, which an instance keeps across rebuilds).
|
||||
fn carry_prop_bindings(from: &Node, to: &mut Node) {
|
||||
to.bound.retain(|k, _| !k.starts_with(PROP_BINDING));
|
||||
to.bound.extend(from.bound.iter().filter(|(k, _)| k.starts_with(PROP_BINDING)).map(|(k, v)| (k.clone(), v.clone())));
|
||||
}
|
||||
|
||||
/// The override group a property-bound field belongs to.
|
||||
fn field_group(field: &str) -> &'static str {
|
||||
match field {
|
||||
@@ -619,6 +632,7 @@ fn sync_instance_depth(doc: &mut Document, inst: NodeId, depth: usize) {
|
||||
fresh.children = order;
|
||||
fresh.transform = root.transform;
|
||||
fresh.kind = root.kind.clone();
|
||||
carry_prop_bindings(&root, &mut fresh);
|
||||
// A nested instance keeps mirroring its layer of the outer main.
|
||||
fresh.source = if inside_instance(doc, inst) { root.source } else { Some(component) };
|
||||
fresh.constraints = root.constraints;
|
||||
|
||||
Reference in New Issue
Block a user