mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-28 20:36:55 -06:00
- Compare changes: a ready-for-dev frame or section keeps a snapshot of itself from just before
its first change (Document::dev_snapshots, saved only while changed; dropped on resolve, re-mark,
other status or delete). `dev.compare {id?, show?}` diffs it layer by layer: added/removed
layers, and property changes formatted like Inspect (`width 120 → 136`, `fill #FF0000 →
#E03030`, text, parent, order, component, auto layout, typography, effects). The compare view
shows before / now side by side or overlaid with a slider, changed layers outlined, the list of
changes and Resolve change.
- Focus view: `dev.focus {id? | direction}` / `dev.unfocus`: one frame drawn and hit alone
(render Options::solo), a bar with name, status, Compare changes, previous / next ready frame and
exit; Escape leaves.
- Annotation categories: defaults plus the file's own with colours (`annotation.categories`,
`addCategory`, `editCategory`, `removeCategory`), `category` on annotations, coloured callouts,
a category filter and editor in the Inspect panel; stored backwards-compatibly.
- Shared widgets::icon_button / canvas_banner / dropdown_lead; has_status moved to the engine.
- Tests: devcompare_tests, devfocus_tests, annotation_categories_tests, doc handoff_tests, render
solo_tests, UI dev_mode_tests.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
37 lines
1.9 KiB
Rust
37 lines
1.9 KiB
Rust
//! Handoff snapshots: a layer's subtree kept, and a copy of the document showing it.
|
|
|
|
use crate::{Document, NodeKind};
|
|
use std::sync::Arc;
|
|
|
|
#[test]
|
|
fn a_snapshot_shows_the_layer_as_it_was() {
|
|
let mut doc = Document::new("d");
|
|
let page = doc.first_page().unwrap();
|
|
let f = doc.create(page, NodeKind::Frame, "Screen", 0.0, 0.0, 100.0, 100.0).unwrap();
|
|
let kept = doc.create(f, NodeKind::Rectangle, "Kept", 0.0, 0.0, 10.0, 10.0).unwrap();
|
|
let gone = doc.create(f, NodeKind::Rectangle, "Gone", 20.0, 0.0, 10.0, 10.0).unwrap();
|
|
let snap = doc.snapshot_subtree(f).unwrap();
|
|
assert_eq!(snap.nodes.iter().map(|n| n.id).collect::<Vec<_>>(), vec![f, kept, gone], "pre-order, the layer first");
|
|
assert!(Arc::ptr_eq(&snap.nodes[1], doc.node_arc(kept).unwrap()), "shared, not copied");
|
|
assert!(doc.snapshot_subtree(crate::NodeId(999)).is_none());
|
|
doc.dev_snapshots.insert(f, Arc::new(snap));
|
|
// Later: one layer edited, one removed, one added.
|
|
doc.get_mut(kept).unwrap().width = 50.0;
|
|
doc.remove(gone).unwrap();
|
|
let new = doc.create(f, NodeKind::Ellipse { start: 0.0, sweep: 1.0, inner: 0.0 }, "New", 0.0, 0.0, 5.0, 5.0).unwrap();
|
|
let before = doc.with_dev_snapshot(f).unwrap();
|
|
assert_eq!(before.node(kept).unwrap().width, 10.0);
|
|
assert!(before.node(gone).is_some());
|
|
assert!(before.node(new).is_none());
|
|
assert_eq!(before.subtree(f), vec![f, kept, gone]);
|
|
assert!(before.dev_snapshots.is_empty());
|
|
assert!(doc.with_dev_snapshot(kept).is_none(), "no snapshot of that layer");
|
|
// Saved compactly: only when there is one.
|
|
let json = serde_json::to_value(&doc).unwrap();
|
|
assert_eq!(json["dev_snapshots"][f.0.to_string()]["nodes"].as_array().map(Vec::len), Some(3));
|
|
let back: Document = serde_json::from_value(json).unwrap();
|
|
assert_eq!(back.dev_snapshots, doc.dev_snapshots);
|
|
doc.dev_snapshots.clear();
|
|
assert!(serde_json::to_value(&doc).unwrap().get("dev_snapshots").is_none());
|
|
}
|