mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-27 03:27:14 -06:00
KEY-SLIDER-NUDGE: scrolling sideways over a slider adjusts it
A trackpad swipe, a tilting wheel or Shift+wheel over a Develop slider nudges it by the wheel/arrow-key steps, without selecting it first (the right panel only scrolls vertically). Only a mostly sideways movement counts, so scrolling the panel leaves the sliders alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
b3d392b499
commit
b36b0d14b7
@@ -1500,6 +1500,36 @@ fn a_selected_develop_slider_accepts_wheel_nudges() {
|
||||
assert!(after > before, "selected exposure did not increase: {before} -> {after}");
|
||||
}
|
||||
|
||||
/// Scrolling sideways over a slider adjusts it without selecting it first: a trackpad swipe
|
||||
/// right raises the value, left lowers it, and Shift+wheel (sideways scrolling with a mouse) does
|
||||
/// the same. A mostly vertical swipe still scrolls the panel and leaves the slider alone.
|
||||
#[test]
|
||||
fn sideways_scrolling_adjusts_the_slider_under_the_pointer() {
|
||||
let mut h = detail("panel.edit");
|
||||
let r = h.request("ui.set", json!({"right": "edit"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
h.settle(SETTLE);
|
||||
let exposure = |h: &Headless| lightcraft_develop::controls::get(&develop(h), "light.exposure").expect("exposure");
|
||||
let scroll = |h: &mut Headless, params: serde_json::Value| {
|
||||
// the pointer rests on the track, the slider is not clicked
|
||||
let r = h.request("ui.hoverWidget", json!({"id": "slider:light.exposure"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
let before = exposure(h);
|
||||
let r = h.request("ui.scroll", params, T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
for _ in 0..10 {
|
||||
h.step();
|
||||
}
|
||||
exposure(h) - before
|
||||
};
|
||||
assert!(scroll(&mut h, json!({"dx": 120.0})) > 0.0, "a swipe right raises the value");
|
||||
assert!(scroll(&mut h, json!({"dx": -120.0})) < 0.0, "a swipe left lowers it");
|
||||
assert!(scroll(&mut h, json!({"dy": 120.0, "shift": true})) > 0.0, "Shift+wheel scrolls sideways");
|
||||
let undo = h.app.session.undo.len();
|
||||
assert_eq!(scroll(&mut h, json!({"dx": 30.0, "dy": -120.0})), 0.0, "a mostly vertical swipe leaves the slider alone");
|
||||
assert_eq!(h.app.session.undo.len(), undo);
|
||||
}
|
||||
|
||||
/// Issue #517: a fast brush stroke (pointer samples several brush widths apart) shows on the photo
|
||||
/// while the button is held as the continuous, feathered band it will be once committed, not as
|
||||
/// separate dabs at the samples with gaps between them.
|
||||
|
||||
@@ -177,8 +177,9 @@ pub(crate) fn shown_value(spec: &ControlSpec, v: f64) -> String {
|
||||
}
|
||||
|
||||
/// A Lightroom slider row (label + value above a track with a hollow ring thumb).
|
||||
/// Double-click the label or thumb to reset. Shift-drag = fine adjustment. Click the value to
|
||||
/// type one: Return or clicking away applies it, Esc keeps the old one.
|
||||
/// Double-click the label or thumb to reset. Shift-drag = fine adjustment. Scroll sideways over
|
||||
/// it to nudge it. Click the value to type one: Return or clicking away applies it, Esc keeps the
|
||||
/// old one.
|
||||
pub fn slider(ui: &mut Ui, spec: &ControlSpec, value: f64, enabled: bool, label_override: Option<&str>) -> SliderOut {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let w = ui.available_width();
|
||||
@@ -351,6 +352,28 @@ pub fn slider(ui: &mut Ui, spec: &ControlSpec, value: f64, enabled: bool, label_
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sideways scrolling (a trackpad swipe, a tilting wheel, Shift+wheel) adjusts the slider under
|
||||
// the pointer, selected or not: the panel only scrolls vertically, so nothing else wants it.
|
||||
// Only a mostly sideways movement counts, so a slightly diagonal swipe that scrolls the panel
|
||||
// leaves the sliders it passes alone. Right raises the value, as dragging the thumb right does.
|
||||
let side_id = id.with("side-rem");
|
||||
let (dx, dy) = ui.input(|i| (i.smooth_scroll_delta.x, i.smooth_scroll_delta.y));
|
||||
if !enabled || typing.is_some() || out.value.is_some() || !ui.rect_contains_pointer(row) || dx.abs() <= dy.abs() {
|
||||
ui.data_mut(|m| m.remove::<f32>(side_id));
|
||||
} else {
|
||||
// the vertical part would scroll the panel and move the slider out from under the pointer
|
||||
ui.input_mut(|i| i.smooth_scroll_delta = egui::Vec2::ZERO);
|
||||
let mut remainder = ui.data(|m| m.get_temp::<f32>(side_id)).unwrap_or(0.0);
|
||||
let steps = wheel_nudges(&mut remainder, dx);
|
||||
ui.data_mut(|m| m.insert_temp(side_id, remainder));
|
||||
let nv = nudged(spec, value, steps);
|
||||
if steps != 0.0 && (nv - value).abs() > 1e-12 {
|
||||
out.value = Some(nv);
|
||||
out.drag_started = true;
|
||||
out.drag_stopped = true;
|
||||
v = nv;
|
||||
}
|
||||
}
|
||||
// Wheel nudges require an explicitly selected slider, unlike regular panel scrolling.
|
||||
// Consume only the vertical component so a trackpad's horizontal scroll still works.
|
||||
let wheel_id = id.with("wheel-rem");
|
||||
|
||||
@@ -667,7 +667,7 @@ From `06-shortcuts.md` part 1. Evidence is our binding; conflicts are explained
|
||||
| KEY-CROP-RESET | Reset crop — ⌥⌘R | P0 | ✅ | `cmd:crop.reset` | |
|
||||
| KEY-STRAIGHTEN | Straighten while held — ⌘ drag | P1 | ✅ | `cmd:crop.straighten`, `crates/ui-egui/src/panels/detail.rs` (`straighten_overlay`) | ⌘-drag in Crop draws a level line; the crop tool stays active |
|
||||
| KEY-SLIDER-RESET | Reset slider — double-click | P0 | ✅ | `crates/ui-egui/src/widgets.rs` | |
|
||||
| KEY-SLIDER-NUDGE | Nudge slider — ↑/↓ | P1 | ✅ | `crates/ui-egui/src/widgets.rs` (`nudged`), `cmd:develop.adjust` | ↑/↓ over any slider: ≈ 1/200 of its range (exposure 0.05, most sliders 1, temperature 50 K); ⇧ ×5; one undo step each |
|
||||
| KEY-SLIDER-NUDGE | Nudge slider — ↑/↓ | P1 | ✅ | `crates/ui-egui/src/widgets.rs` (`nudged`), `cmd:develop.adjust` | ↑/↓ over any slider: ≈ 1/200 of its range (exposure 0.05, most sliders 1, temperature 50 K); ⇧ ×5; one undo step each. Scrolling sideways over any slider (trackpad swipe, tilting wheel, ⇧+wheel) nudges it the same way, one wheel notch a step, without selecting it first; only a mostly sideways movement counts, so scrolling the panel leaves sliders alone (`crates/ui-egui/src/tests_masking.rs`, `sideways_scrolling_adjusts_the_slider_under_the_pointer`) |
|
||||
| KEY-SLIDER-TYPE | Type a slider value | P1 | ✅ | `crates/ui-egui/src/widgets.rs` (`typed_value`), `crates/ui-egui/src/text_field.rs`, `crates/ui-egui/src/widgets/tests_numeric_entry.rs` (`opening_release_honors_return_and_escape_immediately`), `crates/ui-egui/src/tests_keymap.rs` (`opening_numeric_release_keeps_keys_in_the_editor`) | click the value next to any slider's name and type one (`1.5`, `+0,25`, `-20`, `5600 K`): Return or clicking away applies it on the control's steps and range as one undo step, Esc keeps the old value; issue #322; Return/Escape take effect on the opening release, retaining the stored value on Escape; typing stays in the editor without triggering global shortcuts |
|
||||
| KEY-SHORTCUTS | Shortcut list — ⌘/ | P1 | ✅ | `cmd:app.shortcuts` | |
|
||||
| KEY-HELP | Help — F1 | P2 | ✅ | `cmd:app.help` | |
|
||||
@@ -801,6 +801,7 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove
|
||||
| 2026-10-12 | minor | LRC-LIB-MISSING: folder and disk context menus locate a moved tree recursively without relinking missing photos outside it (issue #1194) |
|
||||
| 2026-10-12 | minor | LR-IMP-CAMERA-COVERAGE: Canon PowerShot G9 as-shot white balance from WBInfo (issue #1273); status unchanged (🟡) |
|
||||
| 2026-10-12 | minor | LR-IMP-CAMERA-COVERAGE: Olympus E-10 as-shot white balance and black level from the main maker note (issue #1273); status unchanged (🟡) |
|
||||
| 2026-10-13 | minor | KEY-SLIDER-NUDGE: scrolling sideways over a slider adjusts it |
|
||||
| 2026-10-13 | minor | LR-IMP-CAMERA-COVERAGE: Nikon D90 NEFs drop their 42 filler columns (pink band on the right) and clip at one measured white level; status unchanged (🟡) |
|
||||
| 2026-10-13 | minor | LR-VER-HISTORY, LRC-DEV-HISTORY: History cursor (go to a step without adding one; Previous/Next History Step) |
|
||||
| 2026-10-12 | minor | LR-IMP-FORMATS: the Hasselblad Lunar (a Sony NEX-7 ARW under Make HASSELBLAD) decodes from sensor data instead of opening as its preview; an uncompressed Leaf MOS imports as a preview-only raw instead of a greyscale image of its mosaic (#1275); status unchanged (🟡) |
|
||||
|
||||
Reference in New Issue
Block a user