diff --git a/crates/ui-egui/src/panels/settings.rs b/crates/ui-egui/src/panels/settings.rs index f4dd89bfc..562a90132 100644 --- a/crates/ui-egui/src/panels/settings.rs +++ b/crates/ui-egui/src/panels/settings.rs @@ -117,15 +117,20 @@ fn page_ui(app: &mut EffectcraftApp, ui: &mut egui::Ui, page: &Page, cur: &Value ui.add_sized(vec2(label_w, 18.0), egui::Label::new(format!("{}:", tr(label))).truncate()); let r = match kind { Kind::Int(lo, hi, unit) => { - let mut x = v.as_i64().unwrap_or(0); - // A typed number applies once entered: typing 85 into UI Scale - // doesn't resize the interface to 75 % at its first digit. + // A dragged value applies on release, and a typed one once + // entered: UI Scale doesn't resize the interface under the + // pointer mid-drag (#2582) or at a typed number's first digit. + let held = egui::Id::unique(("settings-drag", key)); + let mut x = ui.data(|d| d.get_temp::(held)).unwrap_or_else(|| v.as_i64().unwrap_or(0)); let drag = egui::DragValue::new(&mut x).range(lo..=hi).speed(0.25).update_while_editing(false); let r = ui.add(crate::widgets::drag_value(drag)); if !unit.is_empty() { ui.label(RichText::new(tr(unit)).color(t.text_dim)); } - if r.changed() { + if r.dragged() { + ui.data_mut(|d| d.insert_temp(held, x)); + } else if r.changed() || r.drag_stopped() { + ui.data_mut(|d| d.remove::(held)); acts.push(Act::Set(key.into(), json!(x))); } r diff --git a/crates/ui-egui/tests/it/ui_panels.rs b/crates/ui-egui/tests/it/ui_panels.rs index db9ef7373..6d06c6bf7 100644 --- a/crates/ui-egui/tests/it/ui_panels.rs +++ b/crates/ui-egui/tests/it/ui_panels.rs @@ -664,3 +664,33 @@ fn transition_presets_apply_from_effects_and_presets() { assert_eq!(fx.name, "Radial Wipe"); assert_eq!(fx.prop("completion").unwrap().keys.len(), 2); } + +/// #2582: dragging Settings' UI Scale doesn't resize the interface under the pointer; the value +/// applies once the button is released. +#[test] +fn ui_scale_applies_when_the_drag_ends() { + let mut h = harness(); + open_settings(&mut h); + let e = h.state().auto.find("settings.appearance.uiScale").expect("the UI Scale field"); + let from = pos2(e.rect[0] + e.rect[2] / 2.0, e.rect[1] + e.rect[3] / 2.0); + h.input_mut().events.push(Event::PointerMoved(from)); + h.input_mut().events.push(Event::PointerButton { pos: from, button: egui::PointerButton::Primary, pressed: true, modifiers: Default::default() }); + h.step(); + for k in 1..=8 { + h.input_mut().events.push(Event::PointerMoved(from + egui::vec2(10.0 * k as f32, 0.0))); + h.step(); + assert_eq!(scale(&h), (100, 1.0), "nothing applies mid-drag"); + } + h.input_mut().events.push(Event::PointerButton { + pos: from + egui::vec2(80.0, 0.0), + button: egui::PointerButton::Primary, + pressed: false, + modifiers: Default::default(), + }); + h.run_steps(4); + let (pct, zoom) = scale(&h); + assert!(pct > 100 && (zoom - pct as f32 / 100.0).abs() < 1e-6, "applied on release: {pct} {zoom}"); + click(&mut h, "settings.cancel"); + h.run_steps(2); + assert_eq!(scale(&h), (100, 1.0)); +}