From ba00e1451021a187f5f20ec38b82c416e540ccca Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Fri, 28 Jun 2024 11:40:42 +0200 Subject: [PATCH 1/4] Add only_clamp_on_input option to DragValue --- crates/egui/src/widgets/drag_value.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 6ed52c1ebdc..5aec3dd3603 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -38,6 +38,7 @@ pub struct DragValue<'a> { prefix: String, suffix: String, clamp_range: RangeInclusive, + only_clamp_on_input: bool, min_decimals: usize, max_decimals: Option, custom_formatter: Option>, @@ -70,6 +71,7 @@ impl<'a> DragValue<'a> { prefix: Default::default(), suffix: Default::default(), clamp_range: f64::NEG_INFINITY..=f64::INFINITY, + only_clamp_on_input: false, min_decimals: 0, max_decimals: None, custom_formatter: None, @@ -94,6 +96,16 @@ impl<'a> DragValue<'a> { self } + /// If `true`, the value will be clamped to the range only upon user input. + /// + /// I.e. if a value outside of the range is set programmatically, it will not be edited. + /// Defaults to false, meaning that the value will be clamped to the range whenever it is set. + #[inline] + pub fn only_clamp_on_input(mut self, only_clamp_on_input: bool) -> Self { + self.only_clamp_on_input = only_clamp_on_input; + self + } + /// Show a prefix before the number, e.g. "x: " #[inline] pub fn prefix(mut self, prefix: impl ToString) -> Self { @@ -362,6 +374,7 @@ impl<'a> Widget for DragValue<'a> { mut get_set_value, speed, clamp_range, + only_clamp_on_input, prefix, suffix, min_decimals, @@ -439,12 +452,17 @@ impl<'a> Widget for DragValue<'a> { }); } + // Apply clamping before applying change, since the set value may not be in range in the first place. + if !only_clamp_on_input || change != 0.0 { + value = clamp_to_range(value, clamp_range.clone()); + } + if change != 0.0 { value += speed * change; value = emath::round_to_decimals(value, auto_decimals); + value = clamp_to_range(value, clamp_range.clone()); } - value = clamp_to_range(value, clamp_range.clone()); if old_value != value { set(&mut get_set_value, value); ui.data_mut(|data| data.remove::(id)); From 4a5b3b4b414f68fbb98634f6c061f575239ed4ea Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Fri, 28 Jun 2024 14:37:04 +0200 Subject: [PATCH 2/4] DragValue clamping is now handled like slider clamping, fix slider docs on what is default --- crates/egui/src/introspection.rs | 4 +- crates/egui/src/memory.rs | 10 +- crates/egui/src/style.rs | 84 ++++++------- crates/egui/src/widgets/color_picker.rs | 2 +- crates/egui/src/widgets/drag_value.rs | 116 ++++++++++-------- crates/egui/src/widgets/slider.rs | 9 +- crates/egui_demo_lib/src/demo/code_example.rs | 8 +- crates/egui_demo_lib/src/demo/context_menu.rs | 4 +- crates/egui_demo_lib/src/demo/plot_demo.rs | 6 +- .../egui_demo_lib/src/demo/widget_gallery.rs | 2 +- examples/custom_plot_manipulation/src/main.rs | 4 +- 11 files changed, 130 insertions(+), 119 deletions(-) diff --git a/crates/egui/src/introspection.rs b/crates/egui/src/introspection.rs index d853b1c6196..7a4c98c2ba9 100644 --- a/crates/egui/src/introspection.rs +++ b/crates/egui/src/introspection.rs @@ -155,7 +155,7 @@ impl Widget for &mut epaint::TessellationOptions { .on_hover_text("Apply feathering to smooth out the edges of shapes. Turn off for small performance gain."); if *feathering { - ui.add(crate::DragValue::new(feathering_size_in_pixels).clamp_range(0.0..=10.0).speed(0.1).suffix(" px")); + ui.add(crate::DragValue::new(feathering_size_in_pixels).range(0.0..=10.0).speed(0.1).suffix(" px")); } }); @@ -165,7 +165,7 @@ impl Widget for &mut epaint::TessellationOptions { ui.label("Spline tolerance"); let speed = 0.01 * *bezier_tolerance; ui.add( - crate::DragValue::new(bezier_tolerance).clamp_range(0.0001..=10.0) + crate::DragValue::new(bezier_tolerance).range(0.0001..=10.0) .speed(speed) ); }); diff --git a/crates/egui/src/memory.rs b/crates/egui/src/memory.rs index e6971b4f8ff..475fe8b85a8 100644 --- a/crates/egui/src/memory.rs +++ b/crates/egui/src/memory.rs @@ -337,16 +337,16 @@ impl Options { .show(ui, |ui| { ui.horizontal(|ui| { ui.label("Line scroll speed"); - ui.add( - crate::DragValue::new(line_scroll_speed).clamp_range(0.0..=f32::INFINITY), - ) - .on_hover_text("How many lines to scroll with each tick of the mouse wheel"); + ui.add(crate::DragValue::new(line_scroll_speed).range(0.0..=f32::INFINITY)) + .on_hover_text( + "How many lines to scroll with each tick of the mouse wheel", + ); }); ui.horizontal(|ui| { ui.label("Scroll zoom speed"); ui.add( crate::DragValue::new(scroll_zoom_speed) - .clamp_range(0.0..=f32::INFINITY) + .range(0.0..=f32::INFINITY) .speed(0.001), ) .on_hover_text("How fast to zoom with ctrl/cmd + scroll"); diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index 1e865e4cc81..cd39cacb6c1 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -571,26 +571,26 @@ impl ScrollStyle { }); ui.horizontal(|ui| { - ui.add(DragValue::new(bar_width).clamp_range(0.0..=32.0)); + ui.add(DragValue::new(bar_width).range(0.0..=32.0)); ui.label("Full bar width"); }); if *floating { ui.horizontal(|ui| { - ui.add(DragValue::new(floating_width).clamp_range(0.0..=32.0)); + ui.add(DragValue::new(floating_width).range(0.0..=32.0)); ui.label("Thin bar width"); }); ui.horizontal(|ui| { - ui.add(DragValue::new(floating_allocated_width).clamp_range(0.0..=32.0)); + ui.add(DragValue::new(floating_allocated_width).range(0.0..=32.0)); ui.label("Allocated width"); }); } ui.horizontal(|ui| { - ui.add(DragValue::new(handle_min_length).clamp_range(0.0..=32.0)); + ui.add(DragValue::new(handle_min_length).range(0.0..=32.0)); ui.label("Minimum handle length"); }); ui.horizontal(|ui| { - ui.add(DragValue::new(bar_outer_margin).clamp_range(0.0..=32.0)); + ui.add(DragValue::new(bar_outer_margin).range(0.0..=32.0)); ui.label("Outer margin"); }); @@ -603,7 +603,7 @@ impl ScrollStyle { if *floating { crate::Grid::new("opacity").show(ui, |ui| { fn opacity_ui(ui: &mut Ui, opacity: &mut f32) { - ui.add(DragValue::new(opacity).speed(0.01).clamp_range(0.0..=1.0)); + ui.add(DragValue::new(opacity).speed(0.01).range(0.0..=1.0)); } ui.label("Opacity"); @@ -626,7 +626,7 @@ impl ScrollStyle { }); } else { ui.horizontal(|ui| { - ui.add(DragValue::new(bar_inner_margin).clamp_range(0.0..=32.0)); + ui.add(DragValue::new(bar_inner_margin).range(0.0..=32.0)); ui.label("Inner margin"); }); } @@ -1418,7 +1418,7 @@ impl Style { ui.label("Animation duration"); ui.add( DragValue::new(animation_time) - .clamp_range(0.0..=1.0) + .range(0.0..=1.0) .speed(0.02) .suffix(" s"), ); @@ -1515,19 +1515,19 @@ impl Spacing { ui.end_row(); ui.label("Indent"); - ui.add(DragValue::new(indent).clamp_range(0.0..=100.0)); + ui.add(DragValue::new(indent).range(0.0..=100.0)); ui.end_row(); ui.label("Slider width"); - ui.add(DragValue::new(slider_width).clamp_range(0.0..=1000.0)); + ui.add(DragValue::new(slider_width).range(0.0..=1000.0)); ui.end_row(); ui.label("Slider rail height"); - ui.add(DragValue::new(slider_rail_height).clamp_range(0.0..=50.0)); + ui.add(DragValue::new(slider_rail_height).range(0.0..=50.0)); ui.end_row(); ui.label("ComboBox width"); - ui.add(DragValue::new(combo_width).clamp_range(0.0..=1000.0)); + ui.add(DragValue::new(combo_width).range(0.0..=1000.0)); ui.end_row(); ui.label("Default area size"); @@ -1535,20 +1535,20 @@ impl Spacing { ui.end_row(); ui.label("TextEdit width"); - ui.add(DragValue::new(text_edit_width).clamp_range(0.0..=1000.0)); + ui.add(DragValue::new(text_edit_width).range(0.0..=1000.0)); ui.end_row(); ui.label("Tooltip wrap width"); - ui.add(DragValue::new(tooltip_width).clamp_range(0.0..=1000.0)); + ui.add(DragValue::new(tooltip_width).range(0.0..=1000.0)); ui.end_row(); ui.label("Default menu width"); - ui.add(DragValue::new(menu_width).clamp_range(0.0..=1000.0)); + ui.add(DragValue::new(menu_width).range(0.0..=1000.0)); ui.end_row(); ui.label("Menu spacing") .on_hover_text("Horizontal spacing between menus"); - ui.add(DragValue::new(menu_spacing).clamp_range(0.0..=10.0)); + ui.add(DragValue::new(menu_spacing).range(0.0..=10.0)); ui.end_row(); ui.label("Checkboxes etc"); @@ -1556,17 +1556,17 @@ impl Spacing { ui.add( DragValue::new(icon_width) .prefix("outer icon width:") - .clamp_range(0.0..=60.0), + .range(0.0..=60.0), ); ui.add( DragValue::new(icon_width_inner) .prefix("inner icon width:") - .clamp_range(0.0..=60.0), + .range(0.0..=60.0), ); ui.add( DragValue::new(icon_spacing) .prefix("spacing:") - .clamp_range(0.0..=10.0), + .range(0.0..=10.0), ); }); ui.end_row(); @@ -1579,7 +1579,7 @@ impl Spacing { ui.horizontal(|ui| { ui.label("Max height of a combo box"); - ui.add(DragValue::new(combo_height).clamp_range(0.0..=1000.0)); + ui.add(DragValue::new(combo_height).range(0.0..=1000.0)); }); ui.collapsing("Scroll Area", |ui| { @@ -1611,15 +1611,15 @@ impl Interaction { .show(ui, |ui| { ui.label("interact_radius") .on_hover_text("Interact with the closest widget within this radius."); - ui.add(DragValue::new(interact_radius).clamp_range(0.0..=20.0)); + ui.add(DragValue::new(interact_radius).range(0.0..=20.0)); ui.end_row(); ui.label("resize_grab_radius_side").on_hover_text("Radius of the interactive area of the side of a window during drag-to-resize"); - ui.add(DragValue::new(resize_grab_radius_side).clamp_range(0.0..=20.0)); + ui.add(DragValue::new(resize_grab_radius_side).range(0.0..=20.0)); ui.end_row(); ui.label("resize_grab_radius_corner").on_hover_text("Radius of the interactive area of the corner of a window during drag-to-resize."); - ui.add(DragValue::new(resize_grab_radius_corner).clamp_range(0.0..=20.0)); + ui.add(DragValue::new(resize_grab_radius_corner).range(0.0..=20.0)); ui.end_row(); ui.label("Tooltip delay").on_hover_text( @@ -1627,7 +1627,7 @@ impl Interaction { ); ui.add( DragValue::new(tooltip_delay) - .clamp_range(0.0..=1.0) + .range(0.0..=1.0) .speed(0.05) .suffix(" s"), ); @@ -1638,7 +1638,7 @@ impl Interaction { ); ui.add( DragValue::new(tooltip_grace_time) - .clamp_range(0.0..=1.0) + .range(0.0..=1.0) .speed(0.05) .suffix(" s"), ); @@ -1996,7 +1996,7 @@ impl TextCursorStyle { ui.add( DragValue::new(on_duration) .speed(0.1) - .clamp_range(0.0..=2.0) + .range(0.0..=2.0) .suffix(" s"), ); ui.end_row(); @@ -2005,7 +2005,7 @@ impl TextCursorStyle { ui.add( DragValue::new(off_duration) .speed(0.1) - .clamp_range(0.0..=2.0) + .range(0.0..=2.0) .suffix(" s"), ); ui.end_row(); @@ -2065,12 +2065,12 @@ fn two_drag_values(value: &mut Vec2, range: std::ops::RangeInclusive) -> im ui.horizontal(|ui| { ui.add( DragValue::new(&mut value.x) - .clamp_range(range.clone()) + .range(range.clone()) .prefix("x: "), ); ui.add( DragValue::new(&mut value.y) - .clamp_range(range.clone()) + .range(range.clone()) .prefix("y: "), ); }) @@ -2212,7 +2212,7 @@ impl Widget for &mut Rounding { ui.checkbox(&mut same, "same"); let mut cr = self.nw; - ui.add(DragValue::new(&mut cr).clamp_range(0.0..=f32::INFINITY)); + ui.add(DragValue::new(&mut cr).range(0.0..=f32::INFINITY)); *self = Rounding::same(cr); }) .response @@ -2222,19 +2222,19 @@ impl Widget for &mut Rounding { crate::Grid::new("rounding").num_columns(2).show(ui, |ui| { ui.label("NW"); - ui.add(DragValue::new(&mut self.nw).clamp_range(0.0..=f32::INFINITY)); + ui.add(DragValue::new(&mut self.nw).range(0.0..=f32::INFINITY)); ui.end_row(); ui.label("NE"); - ui.add(DragValue::new(&mut self.ne).clamp_range(0.0..=f32::INFINITY)); + ui.add(DragValue::new(&mut self.ne).range(0.0..=f32::INFINITY)); ui.end_row(); ui.label("SW"); - ui.add(DragValue::new(&mut self.sw).clamp_range(0.0..=f32::INFINITY)); + ui.add(DragValue::new(&mut self.sw).range(0.0..=f32::INFINITY)); ui.end_row(); ui.label("SE"); - ui.add(DragValue::new(&mut self.se).clamp_range(0.0..=f32::INFINITY)); + ui.add(DragValue::new(&mut self.se).range(0.0..=f32::INFINITY)); ui.end_row(); }); }) @@ -2266,13 +2266,13 @@ impl Widget for &mut Shadow { ui.add( DragValue::new(&mut offset.x) .speed(1.0) - .clamp_range(-100.0..=100.0) + .range(-100.0..=100.0) .prefix("x: "), ); ui.add( DragValue::new(&mut offset.y) .speed(1.0) - .clamp_range(-100.0..=100.0) + .range(-100.0..=100.0) .prefix("y: "), ); ui.end_row(); @@ -2280,14 +2280,14 @@ impl Widget for &mut Shadow { ui.add( DragValue::new(blur) .speed(1.0) - .clamp_range(0.0..=100.0) + .range(0.0..=100.0) .prefix("blur: "), ); ui.add( DragValue::new(spread) .speed(1.0) - .clamp_range(0.0..=100.0) + .range(0.0..=100.0) .prefix("spread: "), ); }); @@ -2302,12 +2302,8 @@ impl Widget for &mut Stroke { let Stroke { width, color } = self; ui.horizontal(|ui| { - ui.add( - DragValue::new(width) - .speed(0.1) - .clamp_range(0.0..=f32::INFINITY), - ) - .on_hover_text("Width"); + ui.add(DragValue::new(width).speed(0.1).range(0.0..=f32::INFINITY)) + .on_hover_text("Width"); ui.color_edit_button_srgba(color); // stroke preview: diff --git a/crates/egui/src/widgets/color_picker.rs b/crates/egui/src/widgets/color_picker.rs index 75df753374a..8943659f923 100644 --- a/crates/egui/src/widgets/color_picker.rs +++ b/crates/egui/src/widgets/color_picker.rs @@ -410,7 +410,7 @@ fn rgba_edit_ui(ui: &mut Ui, [r, g, b, a]: &mut [f32; 4], alpha: Alpha) -> bool DragValue::new(value) .speed(0.003) .prefix(prefix) - .clamp_range(0.0..=1.0) + .range(0.0..=1.0) .custom_formatter(|n, _| format!("{n:.03}")) .ui(ui) } diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 5aec3dd3603..015c648d468 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -37,8 +37,8 @@ pub struct DragValue<'a> { speed: f64, prefix: String, suffix: String, - clamp_range: RangeInclusive, - only_clamp_on_input: bool, + range: RangeInclusive, + clamp_to_range: bool, min_decimals: usize, max_decimals: Option, custom_formatter: Option>, @@ -56,9 +56,7 @@ impl<'a> DragValue<'a> { }); if Num::INTEGRAL { - slf.max_decimals(0) - .clamp_range(Num::MIN..=Num::MAX) - .speed(0.25) + slf.max_decimals(0).range(Num::MIN..=Num::MAX).speed(0.25) } else { slf } @@ -70,8 +68,8 @@ impl<'a> DragValue<'a> { speed: 1.0, prefix: Default::default(), suffix: Default::default(), - clamp_range: f64::NEG_INFINITY..=f64::INFINITY, - only_clamp_on_input: false, + range: f64::NEG_INFINITY..=f64::INFINITY, + clamp_to_range: true, min_decimals: 0, max_decimals: None, custom_formatter: None, @@ -89,20 +87,37 @@ impl<'a> DragValue<'a> { self } - /// Clamp incoming and outgoing values to this range. + /// Sets valid range for the value. + /// + /// By default, the drag value does not show values outside this range, + /// If you want don't want clamp incoming and outgoing values, disable this behavior using [`Slider::clamp_to_range`]. + /// Setting it to `false` will allows users to enter values outside the range by clicking the value and editing it. + #[deprecated = "Use `range` instead"] #[inline] - pub fn clamp_range(mut self, clamp_range: RangeInclusive) -> Self { - self.clamp_range = clamp_range.start().to_f64()..=clamp_range.end().to_f64(); + pub fn clamp_range(mut self, range: RangeInclusive) -> Self { + self.range = range.start().to_f64()..=range.end().to_f64(); self } - /// If `true`, the value will be clamped to the range only upon user input. + /// Sets valid range for dragging the value. /// - /// I.e. if a value outside of the range is set programmatically, it will not be edited. - /// Defaults to false, meaning that the value will be clamped to the range whenever it is set. + /// By default, the drag value does not show values outside this range, + /// If you want don't want clamp incoming and outgoing values, disable this behavior using [`Slider::clamp_to_range`]. + /// Setting it to `false` will allows users to enter values outside the range by clicking the value and editing it. #[inline] - pub fn only_clamp_on_input(mut self, only_clamp_on_input: bool) -> Self { - self.only_clamp_on_input = only_clamp_on_input; + pub fn range(mut self, range: RangeInclusive) -> Self { + self.range = range.start().to_f64()..=range.end().to_f64(); + self + } + + /// If set to `true`, all incoming and outgoing values will be clamped to the slider range. + /// + /// If set to `false`, a value outside of the range that is set programmatically or by user input will not be changed. + /// Dragging will be restricted to the range regardless of this setting. + /// Default: `true`. + #[inline] + pub fn clamp_to_range(mut self, clamp_to_range: bool) -> Self { + self.clamp_to_range = clamp_to_range; self } @@ -169,7 +184,7 @@ impl<'a> DragValue<'a> { /// # egui::__run_test_ui(|ui| { /// # let mut my_i32: i32 = 0; /// ui.add(egui::DragValue::new(&mut my_i32) - /// .clamp_range(0..=((60 * 60 * 24) - 1)) + /// .range(0..=((60 * 60 * 24) - 1)) /// .custom_formatter(|n, _| { /// let n = n as i32; /// let hours = n / (60 * 60); @@ -213,7 +228,7 @@ impl<'a> DragValue<'a> { /// # egui::__run_test_ui(|ui| { /// # let mut my_i32: i32 = 0; /// ui.add(egui::DragValue::new(&mut my_i32) - /// .clamp_range(0..=((60 * 60 * 24) - 1)) + /// .range(0..=((60 * 60 * 24) - 1)) /// .custom_formatter(|n, _| { /// let n = n as i32; /// let hours = n / (60 * 60); @@ -373,8 +388,8 @@ impl<'a> Widget for DragValue<'a> { let Self { mut get_set_value, speed, - clamp_range, - only_clamp_on_input, + range, + clamp_to_range, prefix, suffix, min_decimals, @@ -452,15 +467,13 @@ impl<'a> Widget for DragValue<'a> { }); } - // Apply clamping before applying change, since the set value may not be in range in the first place. - if !only_clamp_on_input || change != 0.0 { - value = clamp_to_range(value, clamp_range.clone()); + if clamp_to_range { + value = clamp_value_to_range(value, range.clone()); } if change != 0.0 { value += speed * change; value = emath::round_to_decimals(value, auto_decimals); - value = clamp_to_range(value, clamp_range.clone()); } if old_value != value { @@ -484,8 +497,10 @@ impl<'a> Widget for DragValue<'a> { Some(parser) => parser(&value_text), None => value_text.parse().ok(), }; - if let Some(parsed_value) = parsed_value { - let parsed_value = clamp_to_range(parsed_value, clamp_range.clone()); + if let Some(mut parsed_value) = parsed_value { + if clamp_to_range { + parsed_value = clamp_value_to_range(parsed_value, range.clone()); + } set(&mut get_set_value, parsed_value); } } @@ -521,8 +536,10 @@ impl<'a> Widget for DragValue<'a> { Some(parser) => parser(&value_text), None => value_text.parse().ok(), }; - if let Some(parsed_value) = parsed_value { - let parsed_value = clamp_to_range(parsed_value, clamp_range.clone()); + if let Some(mut parsed_value) = parsed_value { + if clamp_to_range { + parsed_value = clamp_value_to_range(parsed_value, range.clone()); + } set(&mut get_set_value, parsed_value); } } @@ -537,9 +554,9 @@ impl<'a> Widget for DragValue<'a> { .sense(Sense::click_and_drag()) .min_size(ui.spacing().interact_size); // TODO(emilk): find some more generic solution to `min_size` - let cursor_icon = if value <= *clamp_range.start() { + let cursor_icon = if value <= *range.start() { CursorIcon::ResizeEast - } else if value < *clamp_range.end() { + } else if value < *range.end() { CursorIcon::ResizeHorizontal } else { CursorIcon::ResizeWest @@ -594,7 +611,8 @@ impl<'a> Widget for DragValue<'a> { ); let rounded_new_value = emath::round_to_decimals(rounded_new_value, auto_decimals); - let rounded_new_value = clamp_to_range(rounded_new_value, clamp_range.clone()); + // Dragging will always clamp the value to the range. + let rounded_new_value = clamp_value_to_range(rounded_new_value, range.clone()); set(&mut get_set_value, rounded_new_value); ui.data_mut(|data| data.insert_temp::(id, precise_value)); @@ -614,18 +632,18 @@ impl<'a> Widget for DragValue<'a> { // If either end of the range is unbounded, it's better // to leave the corresponding AccessKit field set to None, // to allow for platform-specific default behavior. - if clamp_range.start().is_finite() { - builder.set_min_numeric_value(*clamp_range.start()); + if range.start().is_finite() { + builder.set_min_numeric_value(*range.start()); } - if clamp_range.end().is_finite() { - builder.set_max_numeric_value(*clamp_range.end()); + if range.end().is_finite() { + builder.set_max_numeric_value(*range.end()); } builder.set_numeric_value_step(speed); builder.add_action(Action::SetValue); - if value < *clamp_range.end() { + if value < *range.end() { builder.add_action(Action::Increment); } - if value > *clamp_range.start() { + if value > *range.start() { builder.add_action(Action::Decrement); } // The name field is set to the current value by the button, @@ -659,7 +677,7 @@ impl<'a> Widget for DragValue<'a> { } } -fn clamp_to_range(x: f64, range: RangeInclusive) -> f64 { +fn clamp_value_to_range(x: f64, range: RangeInclusive) -> f64 { let (mut min, mut max) = (*range.start(), *range.end()); if min.total_cmp(&max) == Ordering::Greater { @@ -677,7 +695,7 @@ fn clamp_to_range(x: f64, range: RangeInclusive) -> f64 { #[cfg(test)] mod tests { - use super::clamp_to_range; + use super::clamp_value_to_range; macro_rules! total_assert_eq { ($a:expr, $b:expr) => { @@ -691,16 +709,16 @@ mod tests { } #[test] - fn test_total_cmp_clamp_to_range() { - total_assert_eq!(0.0_f64, clamp_to_range(-0.0, 0.0..=f64::MAX)); - total_assert_eq!(-0.0_f64, clamp_to_range(0.0, -1.0..=-0.0)); - total_assert_eq!(-1.0_f64, clamp_to_range(-25.0, -1.0..=1.0)); - total_assert_eq!(5.0_f64, clamp_to_range(5.0, -1.0..=10.0)); - total_assert_eq!(15.0_f64, clamp_to_range(25.0, -1.0..=15.0)); - total_assert_eq!(1.0_f64, clamp_to_range(1.0, 1.0..=10.0)); - total_assert_eq!(10.0_f64, clamp_to_range(10.0, 1.0..=10.0)); - total_assert_eq!(5.0_f64, clamp_to_range(5.0, 10.0..=1.0)); - total_assert_eq!(5.0_f64, clamp_to_range(15.0, 5.0..=1.0)); - total_assert_eq!(1.0_f64, clamp_to_range(-5.0, 5.0..=1.0)); + fn test_total_cmp_clamp_value_to_range() { + total_assert_eq!(0.0_f64, clamp_value_to_range(-0.0, 0.0..=f64::MAX)); + total_assert_eq!(-0.0_f64, clamp_value_to_range(0.0, -1.0..=-0.0)); + total_assert_eq!(-1.0_f64, clamp_value_to_range(-25.0, -1.0..=1.0)); + total_assert_eq!(5.0_f64, clamp_value_to_range(5.0, -1.0..=10.0)); + total_assert_eq!(15.0_f64, clamp_value_to_range(25.0, -1.0..=15.0)); + total_assert_eq!(1.0_f64, clamp_value_to_range(1.0, 1.0..=10.0)); + total_assert_eq!(10.0_f64, clamp_value_to_range(10.0, 1.0..=10.0)); + total_assert_eq!(5.0_f64, clamp_value_to_range(5.0, 10.0..=1.0)); + total_assert_eq!(5.0_f64, clamp_value_to_range(15.0, 5.0..=1.0)); + total_assert_eq!(1.0_f64, clamp_value_to_range(-5.0, 5.0..=1.0)); } } diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 61aa56b8548..825cbf85fe6 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -48,9 +48,9 @@ pub enum SliderOrientation { /// Control a number with a slider. /// /// The slider range defines the values you get when pulling the slider to the far edges. -/// By default, the slider can still show values outside this range, -/// and still allows users to enter values outside the range by clicking the slider value and editing it. -/// If you want to clamp incoming and outgoing values, use [`Slider::clamp_to_range`]. +/// By default, the slider does not show values outside this range, +/// If you want don't want clamp incoming and outgoing values, disable this behavior using [`Slider::clamp_to_range`]. +/// Setting it to `false` will allows users to enter values outside the range by clicking the slider value and editing it. /// /// The range can include any numbers, and go from low-to-high or from high-to-low. /// @@ -818,7 +818,8 @@ impl<'a> Slider<'a> { let response = ui.add({ let mut dv = DragValue::new(&mut value) .speed(speed) - .clamp_range(self.clamp_range()) + .range(self.range.clone()) + .clamp_to_range(self.clamp_to_range) .min_decimals(self.min_decimals) .max_decimals_opt(self.max_decimals) .suffix(self.suffix.clone()) diff --git a/crates/egui_demo_lib/src/demo/code_example.rs b/crates/egui_demo_lib/src/demo/code_example.rs index 2859b3ea7dd..18a251077b2 100644 --- a/crates/egui_demo_lib/src/demo/code_example.rs +++ b/crates/egui_demo_lib/src/demo/code_example.rs @@ -43,15 +43,11 @@ impl CodeExample { r#" ui.add( egui::DragValue::new(age) - .clamp_range(0..=120) + .range(0..=120) .suffix(" years"), );"#, ); - ui.add( - egui::DragValue::new(age) - .clamp_range(0..=120) - .suffix(" years"), - ); + ui.add(egui::DragValue::new(age).range(0..=120).suffix(" years")); ui.end_row(); show_code( diff --git a/crates/egui_demo_lib/src/demo/context_menu.rs b/crates/egui_demo_lib/src/demo/context_menu.rs index 3c11da0c122..61cf2c18b73 100644 --- a/crates/egui_demo_lib/src/demo/context_menu.rs +++ b/crates/egui_demo_lib/src/demo/context_menu.rs @@ -95,13 +95,13 @@ impl crate::View for ContextMenus { egui::Grid::new("button_grid").show(ui, |ui| { ui.add( egui::DragValue::new(&mut self.width) - .clamp_range(0.0..=f32::INFINITY) + .range(0.0..=f32::INFINITY) .speed(1.0) .prefix("Width: "), ); ui.add( egui::DragValue::new(&mut self.height) - .clamp_range(0.0..=f32::INFINITY) + .range(0.0..=f32::INFINITY) .speed(1.0) .prefix("Height: "), ); diff --git a/crates/egui_demo_lib/src/demo/plot_demo.rs b/crates/egui_demo_lib/src/demo/plot_demo.rs index b58c3c406a4..25e942925e0 100644 --- a/crates/egui_demo_lib/src/demo/plot_demo.rs +++ b/crates/egui_demo_lib/src/demo/plot_demo.rs @@ -174,7 +174,7 @@ impl LineDemo { ui.add( egui::DragValue::new(circle_radius) .speed(0.1) - .clamp_range(0.0..=f64::INFINITY) + .range(0.0..=f64::INFINITY) .prefix("r: "), ); ui.horizontal(|ui| { @@ -353,7 +353,7 @@ impl MarkerDemo { ui.add( egui::DragValue::new(&mut self.marker_radius) .speed(0.1) - .clamp_range(0.0..=f64::INFINITY) + .range(0.0..=f64::INFINITY) .prefix("Radius: "), ); ui.checkbox(&mut self.automatic_colors, "Automatic colors"); @@ -432,7 +432,7 @@ impl LegendDemo { ui.add( egui::DragValue::new(&mut config.background_alpha) .speed(0.02) - .clamp_range(0.0..=1.0), + .range(0.0..=1.0), ); ui.end_row(); }); diff --git a/crates/egui_demo_lib/src/demo/widget_gallery.rs b/crates/egui_demo_lib/src/demo/widget_gallery.rs index 063ff305e8d..2f59c7caee0 100644 --- a/crates/egui_demo_lib/src/demo/widget_gallery.rs +++ b/crates/egui_demo_lib/src/demo/widget_gallery.rs @@ -87,7 +87,7 @@ impl crate::View for WidgetGallery { (ui.add( egui::DragValue::new(&mut self.opacity) .speed(0.01) - .clamp_range(0.0..=1.0), + .range(0.0..=1.0), ) | ui.label("Opacity")) .on_hover_text("Reduce this value to make widgets semi-transparent"); } diff --git a/examples/custom_plot_manipulation/src/main.rs b/examples/custom_plot_manipulation/src/main.rs index bb62645cbe2..4e218dd233f 100644 --- a/examples/custom_plot_manipulation/src/main.rs +++ b/examples/custom_plot_manipulation/src/main.rs @@ -47,7 +47,7 @@ impl eframe::App for PlotExample { ui.horizontal(|ui| { ui.add( DragValue::new(&mut self.zoom_speed) - .clamp_range(0.1..=2.0) + .range(0.1..=2.0) .speed(0.1), ); ui.label("Zoom speed").on_hover_text("How fast to zoom in and out with the mouse wheel"); @@ -55,7 +55,7 @@ impl eframe::App for PlotExample { ui.horizontal(|ui| { ui.add( DragValue::new(&mut self.scroll_speed) - .clamp_range(0.1..=100.0) + .range(0.1..=100.0) .speed(0.1), ); ui.label("Scroll speed").on_hover_text("How fast to pan with the mouse wheel"); From dd4bcc94874cb96983a3472bc5619f6b163c4374 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Fri, 28 Jun 2024 14:45:35 +0200 Subject: [PATCH 3/4] fix dead code warning --- crates/egui/src/widgets/slider.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 825cbf85fe6..9805c4328e7 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -545,14 +545,6 @@ impl<'a> Slider<'a> { set(&mut self.get_set_value, value); } - fn clamp_range(&self) -> RangeInclusive { - if self.clamp_to_range { - self.range() - } else { - f64::NEG_INFINITY..=f64::INFINITY - } - } - fn range(&self) -> RangeInclusive { self.range.clone() } @@ -871,7 +863,12 @@ impl<'a> Slider<'a> { builder.set_numeric_value_step(step); } builder.add_action(Action::SetValue); - let clamp_range = self.clamp_range(); + + let clamp_range = if self.clamp_to_range { + self.range() + } else { + f64::NEG_INFINITY..=f64::INFINITY + }; if value < *clamp_range.end() { builder.add_action(Action::Increment); } From 04016bb01b2ef4f3320de6e93667f05adbb3b4fb Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Fri, 28 Jun 2024 15:48:23 +0200 Subject: [PATCH 4/4] comment improvements --- crates/egui/src/widgets/drag_value.rs | 12 +++++------- crates/egui/src/widgets/slider.rs | 5 ++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 015c648d468..e46a454fd9e 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -89,9 +89,8 @@ impl<'a> DragValue<'a> { /// Sets valid range for the value. /// - /// By default, the drag value does not show values outside this range, - /// If you want don't want clamp incoming and outgoing values, disable this behavior using [`Slider::clamp_to_range`]. - /// Setting it to `false` will allows users to enter values outside the range by clicking the value and editing it. + /// By default all values are clamped to this range, even when not interacted with. + /// You can change this behavior by passing `false` to [`Slider::clamp_to_range`]. #[deprecated = "Use `range` instead"] #[inline] pub fn clamp_range(mut self, range: RangeInclusive) -> Self { @@ -101,16 +100,15 @@ impl<'a> DragValue<'a> { /// Sets valid range for dragging the value. /// - /// By default, the drag value does not show values outside this range, - /// If you want don't want clamp incoming and outgoing values, disable this behavior using [`Slider::clamp_to_range`]. - /// Setting it to `false` will allows users to enter values outside the range by clicking the value and editing it. + /// By default all values are clamped to this range, even when not interacted with. + /// You can change this behavior by passing `false` to [`Slider::clamp_to_range`]. #[inline] pub fn range(mut self, range: RangeInclusive) -> Self { self.range = range.start().to_f64()..=range.end().to_f64(); self } - /// If set to `true`, all incoming and outgoing values will be clamped to the slider range. + /// If set to `true`, all incoming and outgoing values will be clamped to the sliding [`Self::range`] (if any). /// /// If set to `false`, a value outside of the range that is set programmatically or by user input will not be changed. /// Dragging will be restricted to the range regardless of this setting. diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 9805c4328e7..b055c5465a2 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -48,9 +48,8 @@ pub enum SliderOrientation { /// Control a number with a slider. /// /// The slider range defines the values you get when pulling the slider to the far edges. -/// By default, the slider does not show values outside this range, -/// If you want don't want clamp incoming and outgoing values, disable this behavior using [`Slider::clamp_to_range`]. -/// Setting it to `false` will allows users to enter values outside the range by clicking the slider value and editing it. +/// By default all values are clamped to this range, even when not interacted with. +/// You can change this behavior by passing `false` to [`Slider::clamp_to_range`]. /// /// The range can include any numbers, and go from low-to-high or from high-to-low. ///