Control channel: ui.key arrows pan the view when nothing is selected, as the window does

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Trevor BrownandClaude Fable 5.1 committed 2026-11-01 23:47:48 -05:00
1 parent 53259cf50e
commit ecd900ab37
2 files changed
+29 -1

No files matched your search

+4 -1
View File
@@ -996,7 +996,10 @@ fn ui_key(app: &mut FigApp, ctx: &Context, p: &Value) -> Result<Value, String> {
"ArrowUp" => (0, -1),
_ => (0, 1),
};
let (cmd, params) = if m.cmd || m.ctrl {
// With nothing selected the arrows pan the view, as the window's own key path does.
let (cmd, params) = if app.session.selection().is_empty() {
("view.pan", json!({"dx": dx, "dy": dy, "big": m.shift}))
} else if m.cmd || m.ctrl {
("transform.nudgeSize", json!({"dw": dx, "dh": dy, "big": m.shift}))
} else {
("transform.nudge", json!({"dx": dx, "dy": dy, "big": m.shift}))
@@ -46,3 +46,28 @@ fn control_inspection_rejects_invalid_options_consistently() {
}
}
}
/// `ui.key` with an arrow and nothing selected pans the view, as the window's own key path does
/// (before, it answered that nothing was selected); with a selection it nudges (Shift: farther).
#[test]
fn control_key_arrows_pan_with_nothing_selected() {
let mut u = Ui::new(Session::new());
let r =
call(&mut u, "engine.execute", json!({"command": "shape.rectangle", "params": {"x": 0, "y": 0, "width": 40, "height": 40}})).unwrap()["id"]
.clone();
u.app.run("select.set", json!({"ids": []}));
u.app.run("view.set", json!({"zoom": 2.0, "cx": 0, "cy": 0}));
let view = |u: &Ui| {
let v = &u.app.session.ds().unwrap().view;
(v.cx, v.cy)
};
call(&mut u, "ui.key", json!({"key": "ArrowRight"})).unwrap();
assert_eq!(view(&u), (10.0, 0.0), "20 screen pixels at 200%");
call(&mut u, "ui.key", json!({"key": "ArrowUp", "shift": true})).unwrap();
assert_eq!(view(&u), (10.0, -100.0), "Shift: ten times as far");
u.app.run("select.set", json!({"ids": [r]}));
call(&mut u, "ui.key", json!({"key": "ArrowRight"})).unwrap();
assert_eq!(view(&u), (10.0, -100.0), "with a selection the view stays");
let id = figcraft_engine::params::id_of(&r).unwrap();
assert_eq!(u.app.session.doc().unwrap().world_bounds(id).unwrap().x0, 1.0, "the selection moved instead");
}