From dd1c26b6270652494f90d0406cad49a9823fc7ef Mon Sep 17 00:00:00 2001 From: bflatastic Date: Tue, 13 Oct 2026 03:26:44 +0700 Subject: [PATCH] Part of #1483: sliders in dialogs show their rail The theme's widget fill matches the dialog background, so the sliders of Save for Web, the raster export options, Preferences and the opacity popup showed only their handle. They share one slider widget now, with a visible rail filled up to the handle. --- crates/ui-egui/src/dialogs/png_options.rs | 2 +- crates/ui-egui/src/dialogs/save_for_web.rs | 2 +- crates/ui-egui/src/prefs_dialog.rs | 4 ++-- crates/ui-egui/src/widgets.rs | 15 ++++++++++++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/crates/ui-egui/src/dialogs/png_options.rs b/crates/ui-egui/src/dialogs/png_options.rs index a05ddca3c..93d3284e6 100644 --- a/crates/ui-egui/src/dialogs/png_options.rs +++ b/crates/ui-egui/src/dialogs/png_options.rs @@ -239,7 +239,7 @@ fn quality_row(ui: &mut egui::Ui, d: &mut Dialog, label: &dyn Fn(&mut egui::Ui, label(ui, tl!("Quality:")); let mut q = (d.f64("quality", 90.0) / 10.0).round().clamp(0.0, 10.0) as u8; ui.horizontal(|ui| { - if ui.add(egui::Slider::new(&mut q, 0..=10)).changed() { + if widgets::slider(ui, egui::Slider::new(&mut q, 0..=10)).changed() { d.fields.insert("quality".into(), json!(u32::from(q) * 10)); } label(ui, QUALITY_BANDS[q as usize]); diff --git a/crates/ui-egui/src/dialogs/save_for_web.rs b/crates/ui-egui/src/dialogs/save_for_web.rs index a23af3061..9426fa866 100644 --- a/crates/ui-egui/src/dialogs/save_for_web.rs +++ b/crates/ui-egui/src/dialogs/save_for_web.rs @@ -632,7 +632,7 @@ fn slider_row(ui: &mut egui::Ui, d: &mut Dialog, key: &str, label: &str, suffix: widgets::label_row(ui, label, LABEL_W, |ui| { let mut v = d.f64(key, 0.0).round().clamp(0.0, 100.0) as u8; ui.spacing_mut().slider_width = FIELD_W - 60.0; - if ui.add(egui::Slider::new(&mut v, 0..=100).suffix(suffix)).changed() { + if widgets::slider(ui, egui::Slider::new(&mut v, 0..=100).suffix(suffix)).changed() { d.fields.insert(key.into(), json!(v)); } }); diff --git a/crates/ui-egui/src/prefs_dialog.rs b/crates/ui-egui/src/prefs_dialog.rs index 81a3bfc89..0e2bb93a2 100644 --- a/crates/ui-egui/src/prefs_dialog.rs +++ b/crates/ui-egui/src/prefs_dialog.rs @@ -274,7 +274,7 @@ fn category_fields(ui: &mut egui::Ui, d: &mut Dialog, cat: &str) { labeled(ui, sp.label, |ui| { let mut x = v.as_f64().unwrap_or(min); let new = if sp.key == "uiScaling" { - ui.add(egui::Slider::new(&mut x, min..=max).step_by(0.05).text(tl!("Smaller ↔ Larger"))).changed().then_some(x) + widgets::slider(ui, egui::Slider::new(&mut x, min..=max).step_by(0.05).text(tl!("Smaller ↔ Larger"))).changed().then_some(x) } else { widgets::range_field(ui, sp.key, x, min..=max, &format!(" {unit}"), 3, 110.0) }; @@ -297,7 +297,7 @@ fn category_fields(ui: &mut egui::Ui, d: &mut Dialog, cat: &str) { labeled(ui, sp.label, |ui| { let mut x = v.as_i64().unwrap_or(min); let new = if sp.key == "anchorSize" { - ui.add(egui::Slider::new(&mut x, min..=max).show_value(false).text(tl!("Size"))).changed().then_some(x) + widgets::slider(ui, egui::Slider::new(&mut x, min..=max).show_value(false).text(tl!("Size"))).changed().then_some(x) } else { widgets::range_field(ui, sp.key, x as f64, min as f64..=max as f64, "", 0, 110.0).map(|x| x as i64) }; diff --git a/crates/ui-egui/src/widgets.rs b/crates/ui-egui/src/widgets.rs index 069870645..7019fdcb9 100644 --- a/crates/ui-egui/src/widgets.rs +++ b/crates/ui-egui/src/widgets.rs @@ -895,7 +895,7 @@ pub fn opacity_blend( icons::paint(ui, "chevron-right", r.shrink2(vec2(3.0, 7.0)), if enabled { t.icon } else { t.text_disabled }); egui::Popup::menu(&resp).close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside).show(|ui| { let mut o = opacity.unwrap_or(1.0) * 100.0; - let r = ui.add(egui::Slider::new(&mut o, 0.0..=100.0).show_value(false)); + let r = slider(ui, egui::Slider::new(&mut o, 0.0..=100.0).show_value(false)); let phase = if r.drag_stopped() || (r.changed() && !r.dragged()) { Live::Released } else if r.changed() { @@ -990,6 +990,19 @@ pub fn icon_button_enabled(ui: &mut Ui, icon: &str, tip: &str, selected: bool, e if tip.is_empty() { resp } else { resp.on_hover_text(tl!(tip)) } } +/// A slider whose rail shows, filled up to the handle: the theme's widget fill matches the panel +/// and dialog background, which leaves only the handle visible (#1483). +pub fn slider(ui: &mut Ui, slider: egui::Slider<'_>) -> Response { + let t = Tokens::get(ui.ctx()); + ui.scope(|ui| { + let v = ui.visuals_mut(); + v.widgets.inactive.bg_fill = t.input_border; + v.selection.bg_fill = t.accent; + ui.add(slider.trailing_fill(true)) + }) + .inner +} + /// Regular-weight panel sub-header ("Shape Modes:", "Align Objects:"). pub fn subheader(ui: &mut Ui, text: &str) { let t = Tokens::get(ui.ctx());