Browse Source

Slider: Add step parameter (#1225)

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
pull/1260/head
Alexander 3 years ago
committed by GitHub
parent
commit
62504fface
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 51
      egui/src/widgets/slider.rs
  3. 21
      egui_demo_lib/src/apps/demo/sliders.rs

1
CHANGELOG.md

@ -24,6 +24,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
* Added linked axis support for plots via `plot::LinkedAxisGroup` ([#1184](https://github.com/emilk/egui/pull/1184)). * Added linked axis support for plots via `plot::LinkedAxisGroup` ([#1184](https://github.com/emilk/egui/pull/1184)).
* Added `Response::on_hover_text_at_pointer` as a convenience akin to `Response::on_hover_text` ([1179](https://github.com/emilk/egui/pull/1179)). * Added `Response::on_hover_text_at_pointer` as a convenience akin to `Response::on_hover_text` ([1179](https://github.com/emilk/egui/pull/1179)).
* Added `ui.weak(text)`. * Added `ui.weak(text)`.
* Added `Slider::step_by` ([1255](https://github.com/emilk/egui/pull/1225)).
### Changed 🔧 ### Changed 🔧
* ⚠️ `Context::input` and `Ui::input` now locks a mutex. This can lead to a dead-lock is used in an `if let` binding! * ⚠️ `Context::input` and `Ui::input` now locks a mutex. This can lead to a dead-lock is used in an `if let` binding!

51
egui/src/widgets/slider.rs

@ -71,6 +71,8 @@ pub struct Slider<'a> {
suffix: String, suffix: String,
text: String, text: String,
text_color: Option<Color32>, text_color: Option<Color32>,
/// Sets the minimal step of the widget value
step: Option<f64>,
min_decimals: usize, min_decimals: usize,
max_decimals: Option<usize>, max_decimals: Option<usize>,
} }
@ -113,6 +115,7 @@ impl<'a> Slider<'a> {
suffix: Default::default(), suffix: Default::default(),
text: Default::default(), text: Default::default(),
text_color: None, text_color: None,
step: None,
min_decimals: 0, min_decimals: 0,
max_decimals: None, max_decimals: None,
} }
@ -199,6 +202,16 @@ impl<'a> Slider<'a> {
self self
} }
/// Sets the minimal change of the value.
/// Value `0.0` effectively disables the feature. If the new value is out of range
/// and `clamp_to_range` is enabled, you would not have the ability to change the value.
///
/// Default: `0.0` (disabled).
pub fn step_by(mut self, step: f64) -> Self {
self.step = if step != 0.0 { Some(step) } else { None };
self
}
// TODO: we should also have a "min precision". // TODO: we should also have a "min precision".
/// Set a minimum number of decimals to display. /// Set a minimum number of decimals to display.
/// Normally you don't need to pick a precision, as the slider will intelligently pick a precision for you. /// Normally you don't need to pick a precision, as the slider will intelligently pick a precision for you.
@ -255,6 +268,9 @@ impl<'a> Slider<'a> {
if let Some(max_decimals) = self.max_decimals { if let Some(max_decimals) = self.max_decimals {
value = emath::round_to_decimals(value, max_decimals); value = emath::round_to_decimals(value, max_decimals);
} }
if let Some(step) = self.step {
value = (value / step).round() * step;
}
set(&mut self.get_set_value, value); set(&mut self.get_set_value, value);
} }
@ -330,14 +346,22 @@ impl<'a> Slider<'a> {
let prev_value = self.get_value(); let prev_value = self.get_value();
let prev_position = self.position_from_value(prev_value, position_range.clone()); let prev_position = self.position_from_value(prev_value, position_range.clone());
let new_position = prev_position + kb_step; let new_position = prev_position + kb_step;
let new_value = if self.smart_aim { let new_value = match self.step {
let aim_radius = ui.input().aim_radius(); Some(step) => prev_value + (kb_step as f64 * step),
emath::smart_aim::best_in_range_f64( None if self.smart_aim => {
self.value_from_position(new_position - aim_radius, position_range.clone()), let aim_radius = ui.input().aim_radius();
self.value_from_position(new_position + aim_radius, position_range.clone()), emath::smart_aim::best_in_range_f64(
) self.value_from_position(
} else { new_position - aim_radius,
self.value_from_position(new_position, position_range.clone()) position_range.clone(),
),
self.value_from_position(
new_position + aim_radius,
position_range.clone(),
),
)
}
_ => self.value_from_position(new_position, position_range.clone()),
}; };
self.set_value(new_value); self.set_value(new_value);
} }
@ -438,10 +462,19 @@ impl<'a> Slider<'a> {
} }
fn value_ui(&mut self, ui: &mut Ui, position_range: RangeInclusive<f32>) { fn value_ui(&mut self, ui: &mut Ui, position_range: RangeInclusive<f32>) {
// If `DragValue` is controlled from the keyboard and `step` is defined, set speed to `step`
let change = ui.input().num_presses(Key::ArrowUp) as i32
+ ui.input().num_presses(Key::ArrowRight) as i32
- ui.input().num_presses(Key::ArrowDown) as i32
- ui.input().num_presses(Key::ArrowLeft) as i32;
let speed = match self.step {
Some(step) if change != 0 => step,
_ => self.current_gradient(&position_range),
};
let mut value = self.get_value(); let mut value = self.get_value();
ui.add( ui.add(
DragValue::new(&mut value) DragValue::new(&mut value)
.speed(self.current_gradient(&position_range)) .speed(speed)
.clamp_range(self.clamp_range()) .clamp_range(self.clamp_range())
.min_decimals(self.min_decimals) .min_decimals(self.min_decimals)
.max_decimals_opt(self.max_decimals) .max_decimals_opt(self.max_decimals)

21
egui_demo_lib/src/apps/demo/sliders.rs

@ -11,6 +11,8 @@ pub struct Sliders {
pub logarithmic: bool, pub logarithmic: bool,
pub clamp_to_range: bool, pub clamp_to_range: bool,
pub smart_aim: bool, pub smart_aim: bool,
pub step: f64,
pub use_steps: bool,
pub integer: bool, pub integer: bool,
pub vertical: bool, pub vertical: bool,
pub value: f64, pub value: f64,
@ -24,6 +26,8 @@ impl Default for Sliders {
logarithmic: true, logarithmic: true,
clamp_to_range: false, clamp_to_range: false,
smart_aim: true, smart_aim: true,
step: 10.0,
use_steps: false,
integer: false, integer: false,
vertical: false, vertical: false,
value: 10.0, value: 10.0,
@ -55,6 +59,8 @@ impl super::View for Sliders {
logarithmic, logarithmic,
clamp_to_range, clamp_to_range,
smart_aim, smart_aim,
step,
use_steps,
integer, integer,
vertical, vertical,
value, value,
@ -79,6 +85,7 @@ impl super::View for Sliders {
SliderOrientation::Horizontal SliderOrientation::Horizontal
}; };
let istep = if *use_steps { *step } else { 0.0 };
if *integer { if *integer {
let mut value_i32 = *value as i32; let mut value_i32 = *value as i32;
ui.add( ui.add(
@ -87,7 +94,8 @@ impl super::View for Sliders {
.clamp_to_range(*clamp_to_range) .clamp_to_range(*clamp_to_range)
.smart_aim(*smart_aim) .smart_aim(*smart_aim)
.orientation(orientation) .orientation(orientation)
.text("i32 demo slider"), .text("i32 demo slider")
.step_by(istep),
); );
*value = value_i32 as f64; *value = value_i32 as f64;
} else { } else {
@ -97,7 +105,8 @@ impl super::View for Sliders {
.clamp_to_range(*clamp_to_range) .clamp_to_range(*clamp_to_range)
.smart_aim(*smart_aim) .smart_aim(*smart_aim)
.orientation(orientation) .orientation(orientation)
.text("f64 demo slider"), .text("f64 demo slider")
.step_by(istep),
); );
ui.label( ui.label(
@ -128,6 +137,14 @@ impl super::View for Sliders {
ui.separator(); 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 {
ui.add(egui::DragValue::new(step).speed(1.0));
}
ui.separator();
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Slider type:"); ui.label("Slider type:");
ui.radio_value(integer, true, "i32"); ui.radio_value(integer, true, "i32");

Loading…
Cancel
Save