Toolbar: Alt/Option-click cycles the flyout tool group.

Matches InDesign/Photoshop: plain click keeps the shown tool; Alt-click advances the slot without opening the menu.
This commit is contained in:
tareq committed 2026-10-30 12:00:47 +01:00
1 parent ea08e4c2ba
commit 4652ad2bbc
2 files changed
+41 -2

No files matched your search

+12 -2
View File
@@ -103,19 +103,29 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) {
// on the tool (egui reports releases within 0.8 s as clicks).
let hold_id = egui::Id::unique(("flyout_hold", gi));
let ended_hold = resp.clicked() && ui.data_mut(|d| d.remove_temp::<bool>(hold_id)).unwrap_or(false);
// Plain click selects the shown tool; Alt/Option-click cycles the flyout
// group (InDesign / Photoshop parity with the letter-key cycle).
let alt = ui.input(|i| i.modifiers.alt);
if resp.clicked() && !ended_hold {
chosen = Some(shown.id);
chosen = Some(if g.len() > 1 && alt {
let from = g.iter().position(|tl| tl.id == current).unwrap_or(0);
g[(from + 1) % g.len()].id
} else {
shown.id
});
}
if !resp.is_pointer_button_down_on() {
ui.data_mut(|d| d.remove::<bool>(hold_id));
}
// Double-click a polygon tool: Polygon Settings.
if resp.double_clicked() && matches!(shown.id, "polygon" | "polygonFrame") {
// Alt-clicks only cycle the group: exclude them from double-click dialogs.
if resp.double_clicked() && !alt && matches!(shown.id, "polygon" | "polygonFrame") {
let cur = app.session.execute("tool.polygonSettings", &json!({})).unwrap_or_default();
app.ui.dialog = Some(crate::dialogs::Dialog::new("polygonSettings", cur));
}
// Double-click a transform tool: its Object › Transform dialog.
if resp.double_clicked()
&& !alt
&& let Some(cmd) = transform_dialog_of(shown.id)
{
crate::menus::activate(app, cmd, &Value::Null);
+29
View File
@@ -378,3 +378,32 @@ fn fill_stroke_proxy_keys() {
press(&mut app, &ctx, Key::X, Modifiers::NONE);
assert_eq!(app.ui.stroke_front, front, "X while typing leaves the proxy alone");
}
/// Alt/Option-click cycles a tool group's flyout without opening the menu.
#[test]
fn alt_click_cycles_the_tool_flyout_group() {
use egui::{Event, Modifiers, PointerButton};
use egui_kittest::kittest::Queryable;
let app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
let mut h = crate::test_window::open(app, vec2(1400.0, 900.0));
h.state_mut().app.select_tool("rectangleFrame");
h.run_steps(2);
let at = h.get_by_label("Rectangle Frame Tool (F)").rect().center();
let alt = Modifiers { alt: true, ..Default::default() };
let click = |h: &mut egui_kittest::Harness<'static, crate::test_window::Window>, modifiers: Modifiers| {
h.input_mut().events.push(Event::ModifiersChanged(modifiers));
h.input_mut().events.push(Event::PointerMoved(at));
for pressed in [true, false] {
h.input_mut().events.push(Event::PointerButton { pos: at, button: PointerButton::Primary, pressed, modifiers });
}
h.run_steps(3);
};
click(&mut h, Modifiers::NONE);
assert_eq!(h.state().app.session.tool_id(), "rectangleFrame");
assert!(h.state().app.ui.flyout.is_none());
click(&mut h, alt);
assert_eq!(h.state().app.session.tool_id(), "ellipseFrame", "Alt-click advances the frame group");
assert!(h.state().app.ui.flyout.is_none(), "Alt-click must not open the flyout");
click(&mut h, alt);
assert_eq!(h.state().app.session.tool_id(), "polygonFrame");
}