Fix #299: Alt-clicking a layer's eye or lock toggles the others
In the Layers panel an Alt-click on an eye or lock now applies to the other items beside that row (the other layers for a layer) in one object.setProps step: it hides or locks them while any of them is shown or unlocked, else shows or unlocks them all, as in the reference app. A plain click still toggles only that row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ad8c31b3af
commit
59212cb0d4
|
|
@ -543,6 +543,21 @@ fn row(ui: &mut Ui, view: &View, n: &Node, depth: usize, clip_path: bool, expand
|
|||
}
|
||||
}
|
||||
|
||||
/// Alt-clicking row `n`'s eye or lock (`prop`: `visible` or `locked`) toggles that column for the
|
||||
/// other items beside it (the other layers for a layer), in one step: hides or locks them while
|
||||
/// any of them is shown or unlocked, else shows or unlocks them all. → the action, if there are
|
||||
/// others.
|
||||
fn others_action(doc: &Document, n: &Node, prop: &str) -> Option<(String, Value)> {
|
||||
let siblings = doc.children(doc.parent_of(n.id))?;
|
||||
let others: Vec<&Node> = siblings.iter().map(|c| &**c).filter(|c| c.id != n.id).collect();
|
||||
if others.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let value = if prop == "visible" { !others.iter().any(|o| o.visible) } else { others.iter().any(|o| !o.locked) };
|
||||
let ids: Vec<u64> = others.iter().map(|o| o.id.0).collect();
|
||||
Some(("layer.setProps".into(), json!({ "ids": ids, prop: value })))
|
||||
}
|
||||
|
||||
/// The eye and lock columns of row `n` at `r`.
|
||||
fn eye_and_lock(ui: &mut Ui, view: &View, n: &Node, r: egui::Rect, out: &mut Out) {
|
||||
let t = &view.t;
|
||||
|
|
@ -574,14 +589,18 @@ fn eye_and_lock(ui: &mut Ui, view: &View, n: &Node, r: egui::Rect, out: &mut Out
|
|||
}
|
||||
let m = ui.input(|i| i.modifiers);
|
||||
if er.clicked() {
|
||||
if m.command && n.is_layer() {
|
||||
if m.alt {
|
||||
out.actions.extend(others_action(view.doc, n, "visible"));
|
||||
} else if m.command && n.is_layer() {
|
||||
// Ctrl/Cmd-click: Preview ↔ Outline for this layer.
|
||||
out.actions.push(("layer.setProps".into(), json!({"ids": [n.id.0], "preview": !preview})));
|
||||
} else {
|
||||
out.actions.push(("layer.setProps".into(), json!({"ids": [n.id.0], "visible": !n.visible})));
|
||||
}
|
||||
}
|
||||
if lr.clicked() {
|
||||
if lr.clicked() && m.alt {
|
||||
out.actions.extend(others_action(view.doc, n, "locked"));
|
||||
} else if lr.clicked() {
|
||||
out.actions.push(("layer.setProps".into(), json!({"ids": [n.id.0], "locked": !n.locked})));
|
||||
}
|
||||
// Dragging down a column gives every row it passes this row's new state.
|
||||
|
|
@ -993,6 +1012,41 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alt_clicking_an_eye_or_lock_toggles_the_other_layers() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
let run = |app: &mut VectorcraftApp, id: &str, p: serde_json::Value| app.session.execute(id, &p).unwrap();
|
||||
run(&mut app, "file.new", json!({"width": 200, "height": 200}));
|
||||
run(&mut app, "layer.new", json!({}));
|
||||
run(&mut app, "layer.new", json!({}));
|
||||
let ctx = egui::Context::default();
|
||||
// Rows top first: Layers 3, 2, 1.
|
||||
let (circles, _) = frame(&mut app, &ctx, vec![], false);
|
||||
assert_eq!(circles.len(), 3);
|
||||
let state =
|
||||
|app: &VectorcraftApp| -> Vec<(bool, bool)> { app.session.active().unwrap().doc.layers.iter().map(|l| (l.visible, l.locked)).collect() };
|
||||
let click = |app: &mut VectorcraftApp, at: egui::Pos2, alt: bool| {
|
||||
frame(app, &ctx, vec![egui::Event::PointerMoved(at)], alt);
|
||||
frame(app, &ctx, vec![button(at, true)], alt);
|
||||
frame(app, &ctx, vec![button(at, false)], alt);
|
||||
};
|
||||
let (eye, lock) = (egui::pos2(12.0, circles[1].y), egui::pos2(37.0, circles[1].y));
|
||||
let undo = |app: &VectorcraftApp| app.session.active().unwrap().history.undo.len();
|
||||
let before = undo(&app);
|
||||
// Alt-click Layer 2's eye: Layers 1 and 3 hide in one step; again, they show.
|
||||
click(&mut app, eye, true);
|
||||
assert_eq!(state(&app), [(false, false), (true, false), (false, false)]);
|
||||
assert_eq!(undo(&app), before + 1);
|
||||
click(&mut app, eye, true);
|
||||
assert_eq!(state(&app), [(true, false); 3]);
|
||||
// Alt-click its lock: the others lock.
|
||||
click(&mut app, lock, true);
|
||||
assert_eq!(state(&app), [(true, true), (true, false), (true, true)]);
|
||||
// A plain click still toggles only that layer.
|
||||
click(&mut app, eye, false);
|
||||
assert_eq!(state(&app), [(true, true), (false, false), (true, true)]);
|
||||
}
|
||||
|
||||
/// A document with two rectangles on one layer → (app, layer, [bottom, top]).
|
||||
fn two_rects() -> (VectorcraftApp, NodeId, [NodeId; 2]) {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
|
|
|
|||
Loading…
Reference in New Issue