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

Add methods for custom number formatting in DragValue and Slider #1851

Merged
merged 7 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
39 changes: 35 additions & 4 deletions egui/src/widgets/drag_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ impl MonoState {

// ----------------------------------------------------------------------------

type NumFormatter<'a> = Box<dyn 'a + Fn(f64, RangeInclusive<usize>) -> String>;

// ----------------------------------------------------------------------------

/// Combined into one function (rather than two) to make it easier
/// for the borrow checker.
type GetSetValue<'a> = Box<dyn 'a + FnMut(Option<f64>) -> f64>;
Expand Down Expand Up @@ -56,6 +60,7 @@ pub struct DragValue<'a> {
clamp_range: RangeInclusive<f64>,
min_decimals: usize,
max_decimals: Option<usize>,
custom_formatter: Option<NumFormatter<'a>>,
}

impl<'a> DragValue<'a> {
Expand Down Expand Up @@ -85,6 +90,7 @@ impl<'a> DragValue<'a> {
clamp_range: f64::NEG_INFINITY..=f64::INFINITY,
min_decimals: 0,
max_decimals: None,
custom_formatter: None,
}
}

Expand Down Expand Up @@ -145,6 +151,25 @@ impl<'a> DragValue<'a> {
self.max_decimals = Some(num_decimals);
self
}

/// Set custom formatter defining how numbers are converted into text.
Adanos020 marked this conversation as resolved.
Show resolved Hide resolved
///
/// A custom formatter takes a `f64` for the numeric value and a `RangeInclusive<usize>` representing
/// the decimal range i.e. minimum and maximum number of decimal places shown.
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// # let mut my_i64: i64 = 0;
/// ui.add(egui::DragValue::new(&mut my_i64).custom_formatter(|n, _| format!("{:X}", n as i64)));
/// # });
/// ```
pub fn custom_formatter(
mut self,
formatter: impl 'a + Fn(f64, RangeInclusive<usize>) -> String,
) -> Self {
self.custom_formatter = Some(Box::new(formatter));
self
}
}

impl<'a> Widget for DragValue<'a> {
Expand All @@ -157,6 +182,7 @@ impl<'a> Widget for DragValue<'a> {
suffix,
min_decimals,
max_decimals,
custom_formatter,
} = self;

let shift = ui.input().modifiers.shift_only();
Expand All @@ -174,10 +200,15 @@ impl<'a> Widget for DragValue<'a> {

let max_decimals = max_decimals.unwrap_or(auto_decimals + 2);
let auto_decimals = auto_decimals.clamp(min_decimals, max_decimals);
let value_text = if value == 0.0 {
"0".to_owned()
} else {
emath::format_with_decimals_in_range(value, auto_decimals..=max_decimals)
let value_text = match custom_formatter {
Some(custom_formatter) => custom_formatter(value, auto_decimals..=max_decimals),
None => {
if value == 0.0 {
"0".to_owned()
} else {
emath::format_with_decimals_in_range(value, auto_decimals..=max_decimals)
}
}
};

let kb_edit_id = ui.next_auto_id();
Expand Down
37 changes: 33 additions & 4 deletions egui/src/widgets/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ use crate::*;

// ----------------------------------------------------------------------------

type NumFormatter<'a> = Box<dyn 'a + Fn(f64, RangeInclusive<usize>) -> String>;

// ----------------------------------------------------------------------------

/// Combined into one function (rather than two) to make it easier
/// for the borrow checker.
type GetSetValue<'a> = Box<dyn 'a + FnMut(Option<f64>) -> f64>;
Expand Down Expand Up @@ -75,6 +79,7 @@ pub struct Slider<'a> {
step: Option<f64>,
min_decimals: usize,
max_decimals: Option<usize>,
custom_formatter: Option<NumFormatter<'a>>,
}

impl<'a> Slider<'a> {
Expand Down Expand Up @@ -118,6 +123,7 @@ impl<'a> Slider<'a> {
step: None,
min_decimals: 0,
max_decimals: None,
custom_formatter: None,
}
}

Expand Down Expand Up @@ -241,6 +247,25 @@ impl<'a> Slider<'a> {
self
}

/// Set custom formatter defining how numbers are converted into text.
Adanos020 marked this conversation as resolved.
Show resolved Hide resolved
///
/// A custom formatter takes a `f64` for the numeric value and a `RangeInclusive<usize>` representing
/// the decimal range i.e. minimum and maximum number of decimal places shown.
///
/// ```
/// # egui::__run_test_ui(|ui| {
/// # let mut my_i64: i64 = 0;
/// ui.add(egui::Slider::new(&mut my_i64, 0..=100).custom_formatter(|n, _| format!("{:X}", n as i64)));
/// # });
/// ```
pub fn custom_formatter(
mut self,
formatter: impl 'a + Fn(f64, RangeInclusive<usize>) -> String,
) -> Self {
self.custom_formatter = Some(Box::new(formatter));
self
}

/// Helper: equivalent to `self.precision(0).smallest_positive(1.0)`.
/// If you use one of the integer constructors (e.g. `Slider::i32`) this is called for you,
/// but if you want to have a slider for picking integer values in an `Slider::f64`, use this.
Expand Down Expand Up @@ -468,15 +493,19 @@ impl<'a> Slider<'a> {
_ => self.current_gradient(&position_range),
};
let mut value = self.get_value();
let response = ui.add(
DragValue::new(&mut value)
let response = ui.add({
let dv = DragValue::new(&mut value)
.speed(speed)
.clamp_range(self.clamp_range())
.min_decimals(self.min_decimals)
.max_decimals_opt(self.max_decimals)
.suffix(self.suffix.clone())
.prefix(self.prefix.clone()),
);
.prefix(self.prefix.clone());
match &self.custom_formatter {
Some(fmt) => dv.custom_formatter(fmt),
None => dv,
}
});
if value != self.get_value() {
self.set_value(value);
}
Expand Down