diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ae6e23812ae..67d7b874cd8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG * ⚠️ BREAKING: `egui::Context` now use closures for locking ([#2625](https://github.com/emilk/egui/pull/2625)): * `ctx.input().key_pressed(Key::A)` -> `ctx.input(|i| i.key_pressed(Key::A))` * `ui.memory().toggle_popup(popup_id)` -> `ui.memory_mut(|mem| mem.toggle_popup(popup_id))` +* Add `Slider::trailing_fill` for trailing color behind the circle like a `ProgressBar` ([#2660](https://github.com/emilk/egui/pull/2660)). ### Added ⭐ * Add `Response::drag_started_by` and `Response::drag_released_by` for convenience, similar to `dragged` and `dragged_by` ([#2507](https://github.com/emilk/egui/pull/2507)). diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index a7a3128769d2..6b6c90802679 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -509,6 +509,11 @@ pub struct Visuals { /// Wether or not Grids and Tables should be striped by default /// (have alternating rows differently colored). pub striped: bool, + + /// Show trailing color behind the circle of a [`Slider`]. Default is OFF. + /// + /// Enabling this will affect ALL sliders, and can be enabled/disabled per slider with [`Slider::trailing_fill`]. + pub slider_trailing_fill: bool, } impl Visuals { @@ -768,6 +773,8 @@ impl Visuals { indent_has_left_vline: true, striped: false, + + slider_trailing_fill: false, } } @@ -1333,6 +1340,8 @@ impl Visuals { indent_has_left_vline, striped, + + slider_trailing_fill, } = self; ui.collapsing("Background Colors", |ui| { @@ -1395,6 +1404,8 @@ impl Visuals { ui.checkbox(striped, "By default, add stripes to grids and tables?"); + ui.checkbox(slider_trailing_fill, "Add trailing color to sliders"); + ui.vertical_centered(|ui| reset_button(ui, self)); } } diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index ae5b0c5a8335..a72ee08e03d6 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -84,6 +84,7 @@ pub struct Slider<'a> { max_decimals: Option, custom_formatter: Option>, custom_parser: Option>, + trailing_fill: Option, } impl<'a> Slider<'a> { @@ -129,6 +130,7 @@ impl<'a> Slider<'a> { max_decimals: None, custom_formatter: None, custom_parser: None, + trailing_fill: None, } } @@ -269,6 +271,17 @@ impl<'a> Slider<'a> { self } + /// Display trailing color behind the slider's circle. Default is OFF. + /// + /// This setting can be enabled globally for all sliders with [`Visuals::slider_trailing_fill`]. + /// Toggling it here will override the above setting ONLY for this individual slider. + /// + /// The fill color will be taken from `selection.bg_fill` in your [`Visuals`], the same as a [`ProgressBar`]. + pub fn trailing_fill(mut self, trailing_fill: bool) -> Self { + self.trailing_fill = Some(trailing_fill); + self + } + /// Set custom formatter defining how numbers are converted into text. /// /// A custom formatter takes a `f64` for the numeric value and a `RangeInclusive` representing @@ -616,18 +629,40 @@ impl<'a> Slider<'a> { let rail_radius = ui.painter().round_to_pixel(self.rail_radius_limit(rect)); let rail_rect = self.rail_rect(rect, rail_radius); - let position_1d = self.position_from_value(value, position_range); - let visuals = ui.style().interact(response); - ui.painter().add(epaint::RectShape { - rect: rail_rect, - rounding: ui.visuals().widgets.inactive.rounding, - fill: ui.visuals().widgets.inactive.bg_fill, - stroke: Default::default(), - }); + let widget_visuals = &ui.visuals().widgets; + + ui.painter().rect_filled( + rail_rect, + widget_visuals.inactive.rounding, + widget_visuals.inactive.bg_fill, + ); + let position_1d = self.position_from_value(value, position_range); let center = self.marker_center(position_1d, &rail_rect); + // Decide if we should add trailing fill. + let trailing_fill = self + .trailing_fill + .unwrap_or_else(|| ui.visuals().slider_trailing_fill); + + // Paint trailing fill. + if trailing_fill { + let mut trailing_rail_rect = rail_rect; + + // The trailing rect has to be drawn differently depending on the orientation. + match self.orientation { + SliderOrientation::Vertical => trailing_rail_rect.min.y = center.y, + SliderOrientation::Horizontal => trailing_rail_rect.max.x = center.x, + }; + + ui.painter().rect_filled( + trailing_rail_rect, + widget_visuals.inactive.rounding, + ui.visuals().selection.bg_fill, + ); + } + ui.painter().add(epaint::CircleShape { center, radius: self.handle_radius(rect) + visuals.expansion, diff --git a/crates/egui_demo_lib/src/demo/sliders.rs b/crates/egui_demo_lib/src/demo/sliders.rs index 2b1bbd5b419f..1f565a544d53 100644 --- a/crates/egui_demo_lib/src/demo/sliders.rs +++ b/crates/egui_demo_lib/src/demo/sliders.rs @@ -16,6 +16,7 @@ pub struct Sliders { pub integer: bool, pub vertical: bool, pub value: f64, + pub trailing_fill: bool, } impl Default for Sliders { @@ -31,6 +32,7 @@ impl Default for Sliders { integer: false, vertical: false, value: 10.0, + trailing_fill: false, } } } @@ -64,6 +66,7 @@ impl super::View for Sliders { integer, vertical, value, + trailing_fill, } = self; ui.label("You can click a slider value to edit it with the keyboard."); @@ -95,7 +98,8 @@ impl super::View for Sliders { .smart_aim(*smart_aim) .orientation(orientation) .text("i32 demo slider") - .step_by(istep), + .step_by(istep) + .trailing_fill(*trailing_fill), ); *value = value_i32 as f64; } else { @@ -106,7 +110,8 @@ impl super::View for Sliders { .smart_aim(*smart_aim) .orientation(orientation) .text("f64 demo slider") - .step_by(istep), + .step_by(istep) + .trailing_fill(*trailing_fill), ); ui.label( @@ -126,17 +131,24 @@ impl super::View for Sliders { Slider::new(min, type_min..=type_max) .logarithmic(true) .smart_aim(*smart_aim) - .text("left"), + .text("left") + .trailing_fill(*trailing_fill), ); ui.add( Slider::new(max, type_min..=type_max) .logarithmic(true) .smart_aim(*smart_aim) - .text("right"), + .text("right") + .trailing_fill(*trailing_fill), ); ui.separator(); + ui.checkbox(trailing_fill, "Toggle trailing color"); + ui.label("When enabled, trailing color will be painted up until the circle."); + + ui.separator(); + ui.checkbox(use_steps, "Use steps"); ui.label("When enabled, the minimal value change would be restricted to a given step."); if *use_steps {