Groups: objects of type "group" draw nothing; members carry the group's id in a new `group` field (groups nest). A hidden group hides everything in it (Doc::hidden_in_groups, skipped by the driver), a locked one locks it in the Studio. Removing a group moves its members up into its parent group. isokit check warns about members of missing groups. New `order` op: the whole object order at once (each id once), one undo step. Studio object list as a tree in the document order, front first: each group sits just after its members, so it draws as one block, and ground pieces higher in the list lie on top. Groups fold open and shut; every row has an eye and a lock (shown on hover or when set); a click on a group selects all of it, so a drag on the map moves it all. Group / Ungroup (Ctrl+G, Ctrl+Shift+G), Order up/down (Ctrl+] Ctrl+[, with Shift to the front / back), drag rows above, below or into a group. Group panel: name, zoom, ungroup, to front / back, lock, hide, delete with contents. MCP: group field in the object schema, order op, guidance. Tests: Rust 81 (ops: groups, order, removal; driver: nested hidden groups), Studio 131, web 100.
This commit is contained in:
1 parent
5ec164a633
commit
540b37020c
15 files changed
+573
-30
No files matched your search
@@ -858,6 +858,33 @@ fn piece(id: &str, kind: &str, a: [f64; 2], b: [f64; 2], props: Value) -> Object
|
||||
o
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hidden_groups_hide_what_is_in_them() {
|
||||
let r = Runtime::new(&Bundle::default()).unwrap();
|
||||
let mut g = obj("g", "group", 0.0, 0.0, json!({}));
|
||||
g.hidden = true;
|
||||
let mut inner = obj("inner", "group", 0.0, 0.0, json!({}));
|
||||
inner.group = "g".into();
|
||||
let mut t1 = obj("t1", "tree", 0.0, 0.0, json!({}));
|
||||
t1.group = "inner".into();
|
||||
let mut t2 = obj("t2", "tree", 5.0, 0.0, json!({}));
|
||||
t2.group = "g".into();
|
||||
let doc = Doc {
|
||||
objects: vec![t1, t2, inner, g, obj("t3", "tree", 10.0, 0.0, json!({}))],
|
||||
..Default::default()
|
||||
};
|
||||
let b = r.build("site", 0, &cfg(), &doc).unwrap();
|
||||
// groups draw nothing and warn about nothing
|
||||
assert!(b.scene.warnings.is_empty(), "{:?}", b.scene.warnings);
|
||||
assert_eq!(sprites_of(&b, "g") + sprites_of(&b, "inner"), 0);
|
||||
assert_eq!(sprites_of(&b, "t1") + sprites_of(&b, "t2"), 0);
|
||||
assert_eq!(sprites_of(&b, "t3"), 1);
|
||||
let mut shown = doc.clone();
|
||||
shown.objects[3].hidden = false;
|
||||
let b = r.build("site", 0, &cfg(), &shown).unwrap();
|
||||
assert_eq!(sprites_of(&b, "t1") + sprites_of(&b, "t2"), 2);
|
||||
}
|
||||
|
||||
/// The windows of every route mover piece of object `id`: (piece sprite, windows).
|
||||
fn travel_windows(b: &crate::Built, id: &str) -> Vec<Vec<[f64; 2]>> {
|
||||
fn walk(p: &isokit_core::Prim, out: &mut Vec<Vec<[f64; 2]>>) {
|
||||
|
||||
Reference in new issue
Block a user