#766: port the engine test, a section and click-elsewhere UI case, and the control-protocol note

This commit is contained in:
bflatastic
2026-10-17 23:44:41 +07:00
parent a7da760f9c
commit 76f0edce08
3 changed files with 48 additions and 3 deletions
+23 -1
View File
@@ -1,6 +1,7 @@
//! Frame name labels as pointer targets: a press on a label (its area as the canvas drew it,
//! turned with a rotated frame) selects the frame and drags it in one undo step, hovering it
//! highlights the frame, and labels of locked, hidden, deleted or other pages' frames do nothing.
//! highlights the frame, a double-click asks the UI to rename it there, and labels of locked,
//! hidden, deleted or other pages' frames do nothing.
use figcraft_doc::NodeId;
use figcraft_geom::Point;
@@ -90,3 +91,24 @@ fn labels_of_frames_that_cant_be_picked_do_nothing() {
let flat = [Point::new(1.0, 1.0); 4];
assert_eq!(label_at(s.doc().unwrap(), page, &[(f, nan), (f, flat)], Point::new(1.0, 1.0)), None);
}
#[test]
fn double_clicking_a_label_asks_to_rename_its_frame() {
let (mut s, f, q) = setup();
let c = center(&q);
let before = s.doc().unwrap().world_bounds(f).unwrap();
let undo = s.ds().unwrap().history.undo.len();
for kind in [PointerKind::Down, PointerKind::Up, PointerKind::Down, PointerKind::DoubleClick] {
s.pointer(&ev(kind, c)).unwrap();
}
assert_eq!(s.selection(), vec![f]);
let asked = s.ui_requests.iter().find(|r| r.kind == "canvas.renameLabel").map(|r| id_of(&r.data["id"]));
assert_eq!(asked, Some(Some(f)), "the UI renames the frame at its label");
assert_eq!(s.doc().unwrap().world_bounds(f), Some(before), "not moved");
assert_eq!(s.ds().unwrap().history.undo.len(), undo, "nothing to undo yet");
// Other tools ignore the label.
s.ui_requests.clear();
s.set_tool(crate::tools::ToolId::Hand);
s.pointer(&ev(PointerKind::DoubleClick, c)).unwrap();
assert!(s.ui_requests.iter().all(|r| r.kind != "canvas.renameLabel"));
}
+23 -1
View File
@@ -1,6 +1,6 @@
//! Frame name labels on the canvas, driven through egui headless: an upright frame's label sits
//! just above its top-left corner, a rotated frame's runs along its turned top edge, and pressing
//! either label selects and drags its frame.
//! either label selects and drags its frame; double-clicking one renames the frame or section there.
use egui::{Event, Pos2, pos2, vec2};
use figcraft_doc::NodeId;
@@ -134,3 +134,25 @@ fn escape_leaves_a_label_rename_with_the_old_name() {
assert_eq!(name(&u, b), "Turned");
assert!(u.app.ui.rename_label.is_none());
}
#[test]
fn a_sections_label_renames_it_and_a_click_elsewhere_commits() {
let mut s = Session::new();
let a = id(s.execute("node.create", &json!({"type": "section", "x": 0, "y": 0, "width": 300, "height": 200, "name": "Area"})).unwrap());
s.execute("select.none", &json!({})).unwrap();
let mut u = Ui::new(s);
u.frame(vec![]);
let undo = u.app.session.ds().unwrap().history.undo.len();
double_click_label(&mut u, a);
assert_eq!(u.app.ui.rename_label.map(|r| r.id), Some(a), "a field over the section's label");
assert_eq!(u.app.session.selection(), vec![a]);
u.frame(vec![Event::Text("Zone".into())]);
let at = mid(&label(&u, a));
let away = pos2(at.x + 200.0, at.y + 500.0);
u.button(away, true);
u.button(away, false);
u.frame(vec![]);
assert_eq!(name(&u, a), "Zone", "a click on the canvas commits");
assert!(u.app.ui.rename_label.is_none());
assert_eq!(u.app.session.ds().unwrap().history.undo.len(), undo + 1, "one undo step");
}
+2 -1
View File
@@ -198,7 +198,8 @@ A mouse gesture with the current tool. `kind`: `down`, `move`, `up`, `click`, `d
(`x`, `y`) or screen pixels (`sx`, `sy`). `pressure` (0–1) is pen pressure (the Pencil records
it); a drag's pressure goes from `pressure` to `pressureTo`. Returns `{selection, tool}`. With the Move and Scale
tools, a press on a frame's or section's name label (as the canvas last drew it, along a rotated
frame's top edge) selects and drags that frame.
frame's top edge) selects and drags that frame; a double-click there renames the frame in place in
the desktop app (the name field opens over the label).
```json
{"id":4,"method":"engine.execute","params":{"command":"tool.set","params":{"tool":"ellipse"}}}