Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slider: Add step parameter #1225

Merged
merged 9 commits into from Feb 13, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -22,6 +22,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
* Added `Plot::allow_boxed_zoom()`, `Plot::boxed_zoom_pointer()` for boxed zooming on plots ([#1188](https://github.com/emilk/egui/pull/1188)).
* 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 `Slider::step_by` ([1255](https://github.com/emilk/egui/pull/1225))

### Changed 🔧
* ⚠️ `Context::input` and `Ui::input` now locks a mutex. This can lead to a dead-lock is used in an `if let` binding!
Expand Down
59 changes: 50 additions & 9 deletions egui/src/widgets/slider.rs
Expand Up @@ -71,6 +71,8 @@ pub struct Slider<'a> {
suffix: String,
text: String,
text_color: Option<Color32>,
/// Sets the minimal step of the widget value
step: Option<f64>,
min_decimals: usize,
max_decimals: Option<usize>,
}
Expand Down Expand Up @@ -113,6 +115,7 @@ impl<'a> Slider<'a> {
suffix: Default::default(),
text: Default::default(),
text_color: None,
step: None,
min_decimals: 0,
max_decimals: None,
}
Expand Down Expand Up @@ -199,6 +202,21 @@ impl<'a> Slider<'a> {
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 {
let step = if step != 0.0 {
Some(step)
} else {
None
};
self.step = step;
self
}

// TODO: we should also have a "min precision".
/// 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.
Expand Down Expand Up @@ -255,6 +273,12 @@ impl<'a> Slider<'a> {
if let Some(max_decimals) = self.max_decimals {
value = emath::round_to_decimals(value, max_decimals);
}
if let Some(step) = self.step {
let remainer = value % step;
if remainer != 0.0 {
value -= remainer;
};
emilk marked this conversation as resolved.
Show resolved Hide resolved
}
set(&mut self.get_set_value, value);
}

Expand Down Expand Up @@ -330,14 +354,22 @@ impl<'a> Slider<'a> {
let prev_value = self.get_value();
let prev_position = self.position_from_value(prev_value, position_range.clone());
let new_position = prev_position + kb_step;
let new_value = if self.smart_aim {
let aim_radius = ui.input().aim_radius();
emath::smart_aim::best_in_range_f64(
self.value_from_position(new_position - aim_radius, position_range.clone()),
self.value_from_position(new_position + aim_radius, position_range.clone()),
)
} else {
self.value_from_position(new_position, position_range.clone())
let new_value = match self.step {
Some(step) => prev_value + (kb_step as f64 * step),
None if self.smart_aim => {
let aim_radius = ui.input().aim_radius();
emath::smart_aim::best_in_range_f64(
self.value_from_position(
new_position - aim_radius,
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);
}
Expand Down Expand Up @@ -438,10 +470,19 @@ impl<'a> Slider<'a> {
}

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();
ui.add(
DragValue::new(&mut value)
.speed(self.current_gradient(&position_range))
.speed(speed)
.clamp_range(self.clamp_range())
.min_decimals(self.min_decimals)
.max_decimals_opt(self.max_decimals)
Expand Down
21 changes: 19 additions & 2 deletions egui_demo_lib/src/apps/demo/sliders.rs
Expand Up @@ -11,6 +11,8 @@ pub struct Sliders {
pub logarithmic: bool,
pub clamp_to_range: bool,
pub smart_aim: bool,
pub step: f64,
pub use_steps: bool,
pub integer: bool,
pub vertical: bool,
pub value: f64,
Expand All @@ -24,6 +26,8 @@ impl Default for Sliders {
logarithmic: true,
clamp_to_range: false,
smart_aim: true,
step: 10.0,
use_steps: false,
integer: false,
vertical: false,
value: 10.0,
Expand Down Expand Up @@ -55,6 +59,8 @@ impl super::View for Sliders {
logarithmic,
clamp_to_range,
smart_aim,
step,
use_steps,
integer,
vertical,
value,
Expand All @@ -79,6 +85,7 @@ impl super::View for Sliders {
SliderOrientation::Horizontal
};

let istep = if *use_steps { *step } else { 0.0 };
if *integer {
let mut value_i32 = *value as i32;
ui.add(
Expand All @@ -87,7 +94,8 @@ impl super::View for Sliders {
.clamp_to_range(*clamp_to_range)
.smart_aim(*smart_aim)
.orientation(orientation)
.text("i32 demo slider"),
.text("i32 demo slider")
.step_by(istep),
);
*value = value_i32 as f64;
} else {
Expand All @@ -97,7 +105,8 @@ impl super::View for Sliders {
.clamp_to_range(*clamp_to_range)
.smart_aim(*smart_aim)
.orientation(orientation)
.text("f64 demo slider"),
.text("f64 demo slider")
.step_by(istep),
);

ui.label(
Expand Down Expand Up @@ -128,6 +137,14 @@ impl super::View for Sliders {

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.label("Slider type:");
ui.radio_value(integer, true, "i32");
Expand Down