ui: scrub hot text from the slider range (#2097)

This commit is contained in:
Madhav Agarwal
2026-10-22 19:05:30 +05:30
parent 9a51a05e1b
commit ffe3c913e1
3 changed files with 23 additions and 5 deletions
+1 -4
View File
@@ -337,10 +337,7 @@ fn prop_row(
ParamUi::Percent => "%",
_ => "",
};
let speed = match &prop.ui {
ParamUi::Slider { slider_min, slider_max, .. } => ((slider_max - slider_min) / 300.0).clamp(0.001, 50.0),
_ => 0.5,
};
let speed = widgets::slider_scrub_speed(&prop.ui);
let (vr, nv, _) = widgets::hot_number_at(
ui,
pos2(vx, cy - 9.0),
+1 -1
View File
@@ -4105,7 +4105,7 @@ fn value_editor(
match value {
Value::Scalar(v) => {
let (min, max, dec, speed) = match &prop.ui {
ParamUi::Slider { min, max, decimals, .. } => (*min, *max, *decimals as usize, ((max - min) / 400.0).clamp(0.01, 10.0)),
ParamUi::Slider { min, max, decimals, .. } => (*min, *max, *decimals as usize, widgets::slider_scrub_speed(&prop.ui)),
ParamUi::Percent => (-1e6, 1e6, 1, 0.5),
_ => (-1e9, 1e9, 1, 1.0),
};
+21
View File
@@ -2,6 +2,8 @@
use egui::{Align2, Color32, Rect, Response, Sense, Stroke, StrokeKind, Ui, pos2, vec2};
use effectcraft_project::ParamUi;
use crate::automation::Registry;
use crate::icons::{self, Icon};
use crate::theme::Tokens;
@@ -145,6 +147,16 @@ pub fn proportional_scrub(m: egui::Modifiers) -> bool {
m.command && m.alt
}
/// How far one pointer pixel scrubs a hot-text field: the property's slider (soft) range over
/// 300 px. The Timeline and Effect Controls share this so they cannot drift; a large hard range
/// only allows typing big values, it must not make dragging coarse (#2097).
pub fn slider_scrub_speed(ui: &ParamUi) -> f64 {
match ui {
ParamUi::Slider { slider_min, slider_max, .. } => ((slider_max - slider_min) / 300.0).clamp(0.001, 50.0),
_ => 0.5,
}
}
/// [`hot_number_at`] for a whole number (an angle's revolutions): a drag steps it once every
/// `1 / speed` pixels however slowly the pointer moves (the fractions add up between frames),
/// and a typed value is truncated. Returns (rect, Some(new value) when changed, drag finished).
@@ -666,6 +678,15 @@ pub(crate) fn constrained(c: &[f64], d: usize, v: f64) -> Vec<f64> {
mod tests {
use super::*;
/// #2097: the drag speed comes from the slider range, not a much wider hard range.
#[test]
fn slider_scrub_speed_uses_the_slider_range() {
let slider = |min, max, slider_min, slider_max| ParamUi::Slider { min, max, slider_min, slider_max, decimals: 1 };
assert!((slider_scrub_speed(&slider(0.0, 10_000.0, 0.0, 1_000.0)) - 1_000.0 / 300.0).abs() < 1e-9);
assert!((slider_scrub_speed(&slider(0.0, 1.0e9, 0.0, 1.0)) - 1.0 / 300.0).abs() < 1e-9);
assert_eq!(slider_scrub_speed(&ParamUi::Number), 0.5);
}
/// #488: an inline editor selects its whole text only as it opens. Should it be without the
/// keyboard for a frame later (an input method, another handler), it takes the keyboard back
/// with the caret where the user put it instead of selecting everything again, which made