diff --git a/crates/ui-egui/src/shortcuts.rs b/crates/ui-egui/src/shortcuts.rs index 593841991..129fb1d9e 100644 --- a/crates/ui-egui/src/shortcuts.rs +++ b/crates/ui-egui/src/shortcuts.rs @@ -308,6 +308,10 @@ fn keyboard_owned(app: &LightcraftApp, ctx: &egui::Context) -> bool { return ctx.input(|input| input.key_pressed(Key::Escape)) && app.widgets.iter().any(|(widget, _)| widget.starts_with("sliderField:") && crate::text_field::was_editing(ctx, widget)); } + // a selected slider keeps its arrow keys; everything else is a shortcut + if crate::widgets::slider_has_focus(ctx) { + return ctx.input(|input| [Key::ArrowLeft, Key::ArrowRight, Key::ArrowUp, Key::ArrowDown].iter().any(|key| input.key_pressed(*key))); + } let chrome = app .ui .docking diff --git a/crates/ui-egui/src/tests_dialog_fit.rs b/crates/ui-egui/src/tests_dialog_fit.rs index d2d69c056..5c4f1a83f 100644 --- a/crates/ui-egui/src/tests_dialog_fit.rs +++ b/crates/ui-egui/src/tests_dialog_fit.rs @@ -93,9 +93,10 @@ fn export_dialog_is_unchanged_in_a_tall_window() { let h = export_dialog([1600.0, 1000.0]); assert_fits(&h, "Export at 1600×1000"); let dialog = rect(&h, "dialog:window"); - // (846 × 500.6 before #781: the whole dialog, nothing scrolled away) + // (846 tall as before #781: the whole dialog, nothing scrolled away; 546 wide since the + // watermark's nine positions, #833) assert!((dialog.height() - 846.0).abs() <= 1.0, "{dialog:?}"); - assert!((dialog.width() - 500.6).abs() <= 1.0, "{dialog:?}"); + assert!((dialog.width() - 546.0).abs() <= 1.0, "{dialog:?}"); } // Scenario: other long dialogs fit a short window too, with their buttons on screen diff --git a/crates/ui-egui/src/tests_masking.rs b/crates/ui-egui/src/tests_masking.rs index e5edf3c7a..8024c62c5 100644 --- a/crates/ui-egui/src/tests_masking.rs +++ b/crates/ui-egui/src/tests_masking.rs @@ -1337,6 +1337,9 @@ fn color_range_pick_button_samples_the_photo() { #[test] fn a_selected_develop_slider_accepts_wheel_nudges() { let mut h = detail("panel.edit"); + // the demo may open on the Edit panel already, which `panel.edit` then toggles shut + let r = h.request("ui.set", json!({"right": "edit"}), T); + assert_eq!(r["ok"], true, "{r}"); h.settle(SETTLE); let name = "slider:light.exposure"; let panel = h.app.widgets.iter().find(|(id, _)| id == "panel:right_panel").unwrap().1; diff --git a/crates/ui-egui/src/widgets.rs b/crates/ui-egui/src/widgets.rs index ea187591b..0872b2ec4 100644 --- a/crates/ui-egui/src/widgets.rs +++ b/crates/ui-egui/src/widgets.rs @@ -187,6 +187,7 @@ pub fn slider(ui: &mut Ui, spec: &ControlSpec, value: f64, enabled: bool, label_ // opt-in so hovering an unfocused slider still scrolls the containing panel. if enabled && (resp.clicked() || resp.drag_started()) { resp.request_focus(); + ui.data_mut(|d| d.insert_temp(focused_slider_key(), id)); } // screen readers: a slider named after its control, with its value let label_text = crate::i18n::tr(label_override.unwrap_or(spec.label)).to_string(); @@ -726,3 +727,14 @@ pub(crate) fn elide_head(text: &str, max: f32, width: impl Fn(&str) -> f32) -> S #[cfg(test)] #[path = "widgets/tests_numeric_entry.rs"] mod numeric_entry_tests; + +fn focused_slider_key() -> egui::Id { + egui::Id::new("lightcraft-focused-slider") +} + +/// Whether the widget with keyboard focus is a develop slider a click selected. It owns only the +/// arrow keys (and the wheel): every other shortcut still works, as in Lightroom after a drag. +pub fn slider_has_focus(ctx: &egui::Context) -> bool { + let focused = ctx.memory(|m| m.focused()); + focused.is_some() && focused == ctx.data(|d| d.get_temp::(focused_slider_key())) +}