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 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
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` and `Slider::disable_step()` ([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
81 changes: 65 additions & 16 deletions egui/src/widgets/slider.rs
Original file line number Diff line number Diff line change
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,28 @@ impl<'a> Slider<'a> {
self
}

/// Sets the minimal change of the value.
/// If `clamp_to_range` is enabled, `step` must be less than a maximum between the start and
/// the end of the range; otherwise, the step would be left unchanged.
/// Without `clamp_to_range` enabled, `step` can be any value.
///
/// Default: `None`.
pub fn step_by(mut self, step: f64) -> Self {
let max = self.range.end().abs().max(self.range.start().abs());
let step = match self.clamp_to_range {
emilk marked this conversation as resolved.
Show resolved Hide resolved
true if (step.abs() > max) => None,
_ => Some(step),
};
self.step = step;
self
}

/// Disable the `step_by` feature
pub fn disable_step(mut self) -> Self {
emilk marked this conversation as resolved.
Show resolved Hide resolved
self.step = None;
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 @@ -247,13 +272,20 @@ impl<'a> Slider<'a> {
}

fn set_value(&mut self, mut value: f64) {
if self.clamp_to_range {
let start = *self.range.start();
let end = *self.range.end();
value = value.clamp(start.min(end), start.max(end));
}
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
} else {
if self.clamp_to_range {
emilk marked this conversation as resolved.
Show resolved Hide resolved
let start = *self.range.start();
let end = *self.range.end();
value = value.clamp(start.min(end), start.max(end));
}
if let Some(max_decimals) = self.max_decimals {
value = emath::round_to_decimals(value, max_decimals);
}
}
set(&mut self.get_set_value, value);
}
Expand Down Expand Up @@ -330,14 +362,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 +478,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
17 changes: 16 additions & 1 deletion egui_demo_lib/src/apps/demo/widget_gallery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct WidgetGallery {
boolean: bool,
radio: Enum,
scalar: f32,
step: f64,
string: String,
color: egui::Color32,
animate_progress_bar: bool,
Expand All @@ -29,6 +30,7 @@ impl Default for WidgetGallery {
boolean: false,
radio: Enum::First,
scalar: 42.0,
step: 0.0,
string: Default::default(),
color: egui::Color32::LIGHT_BLUE.linear_multiply(0.5),
animate_progress_bar: false,
Expand Down Expand Up @@ -99,6 +101,7 @@ impl WidgetGallery {
boolean,
radio,
scalar,
step,
string,
color,
animate_progress_bar,
Expand Down Expand Up @@ -166,8 +169,20 @@ impl WidgetGallery {
});
ui.end_row();

ui.add(doc_link_label("Slider step", "Slider"));
ui.add(egui::Slider::new(step, 0.0..=90.0));
ui.end_row();

ui.add(doc_link_label("Slider", "Slider"));
ui.add(egui::Slider::new(scalar, 0.0..=360.0).suffix("°"));
if *step != 0.0 {
ui.add(
egui::Slider::new(scalar, 0.0..=360.0)
.suffix("°")
.step_by(*step),
);
} else {
ui.add(egui::Slider::new(scalar, 0.0..=360.0).suffix("°"));
}
Gordon01 marked this conversation as resolved.
Show resolved Hide resolved
ui.end_row();

ui.add(doc_link_label("DragValue", "DragValue"));
Expand Down