Batch 30: a selected slider keeps only its arrow keys, so shortcuts work after a slider click (#884); tests follow the merged dialog and panel state

#884 focuses a develop slider on click so the wheel and arrows adjust it, but a focused widget
owned the whole keyboard, so after touching a slider no shortcut fired (O for the mask overlay,
caught by mask_adjustments_hide_overlay_without_disabling_the_mask). Now a selected slider owns
the arrow keys only. The wheel test opens the Edit panel explicitly (the demo may start on it, and
panel.edit then toggles it shut), and the Export dialog snapshot is 546 px wide since #833's
nine watermark positions.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01BKWB9TCnvzJHV6xMLAj2J4
This commit is contained in:
Claude committed 2026-10-11 12:59:15 +00:00
1 parent 870eaa74e6
commit 4ff1d9761d
4 files changed
+22 -2

No files matched your search

+4
View File
@@ -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
+3 -2
View File
@@ -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
+3
View File
@@ -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;
+12
View File
@@ -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::<egui::Id>(focused_slider_key()))
}