Add methods for custom number formatting in DragValue
and Slider
(#1851)
This commit is contained in:
parent
c02fbfe973
commit
36cdae98df
2 changed files with 68 additions and 8 deletions
|
@ -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
|
/// Combined into one function (rather than two) to make it easier
|
||||||
/// for the borrow checker.
|
/// for the borrow checker.
|
||||||
type GetSetValue<'a> = Box<dyn 'a + FnMut(Option<f64>) -> f64>;
|
type GetSetValue<'a> = Box<dyn 'a + FnMut(Option<f64>) -> f64>;
|
||||||
|
@ -56,6 +60,7 @@ pub struct DragValue<'a> {
|
||||||
clamp_range: RangeInclusive<f64>,
|
clamp_range: RangeInclusive<f64>,
|
||||||
min_decimals: usize,
|
min_decimals: usize,
|
||||||
max_decimals: Option<usize>,
|
max_decimals: Option<usize>,
|
||||||
|
custom_formatter: Option<NumFormatter<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DragValue<'a> {
|
impl<'a> DragValue<'a> {
|
||||||
|
@ -85,6 +90,7 @@ impl<'a> DragValue<'a> {
|
||||||
clamp_range: f64::NEG_INFINITY..=f64::INFINITY,
|
clamp_range: f64::NEG_INFINITY..=f64::INFINITY,
|
||||||
min_decimals: 0,
|
min_decimals: 0,
|
||||||
max_decimals: None,
|
max_decimals: None,
|
||||||
|
custom_formatter: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +151,25 @@ impl<'a> DragValue<'a> {
|
||||||
self.max_decimals = Some(num_decimals);
|
self.max_decimals = Some(num_decimals);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set custom formatter defining how numbers are converted into text.
|
||||||
|
///
|
||||||
|
/// 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> {
|
impl<'a> Widget for DragValue<'a> {
|
||||||
|
@ -157,6 +182,7 @@ impl<'a> Widget for DragValue<'a> {
|
||||||
suffix,
|
suffix,
|
||||||
min_decimals,
|
min_decimals,
|
||||||
max_decimals,
|
max_decimals,
|
||||||
|
custom_formatter,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let shift = ui.input().modifiers.shift_only();
|
let shift = ui.input().modifiers.shift_only();
|
||||||
|
@ -174,10 +200,15 @@ impl<'a> Widget for DragValue<'a> {
|
||||||
|
|
||||||
let max_decimals = max_decimals.unwrap_or(auto_decimals + 2);
|
let max_decimals = max_decimals.unwrap_or(auto_decimals + 2);
|
||||||
let auto_decimals = auto_decimals.clamp(min_decimals, max_decimals);
|
let auto_decimals = auto_decimals.clamp(min_decimals, max_decimals);
|
||||||
let value_text = if value == 0.0 {
|
let value_text = match custom_formatter {
|
||||||
"0".to_owned()
|
Some(custom_formatter) => custom_formatter(value, auto_decimals..=max_decimals),
|
||||||
} else {
|
None => {
|
||||||
emath::format_with_decimals_in_range(value, auto_decimals..=max_decimals)
|
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();
|
let kb_edit_id = ui.next_auto_id();
|
||||||
|
|
|
@ -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
|
/// Combined into one function (rather than two) to make it easier
|
||||||
/// for the borrow checker.
|
/// for the borrow checker.
|
||||||
type GetSetValue<'a> = Box<dyn 'a + FnMut(Option<f64>) -> f64>;
|
type GetSetValue<'a> = Box<dyn 'a + FnMut(Option<f64>) -> f64>;
|
||||||
|
@ -75,6 +79,7 @@ pub struct Slider<'a> {
|
||||||
step: Option<f64>,
|
step: Option<f64>,
|
||||||
min_decimals: usize,
|
min_decimals: usize,
|
||||||
max_decimals: Option<usize>,
|
max_decimals: Option<usize>,
|
||||||
|
custom_formatter: Option<NumFormatter<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Slider<'a> {
|
impl<'a> Slider<'a> {
|
||||||
|
@ -118,6 +123,7 @@ impl<'a> Slider<'a> {
|
||||||
step: None,
|
step: None,
|
||||||
min_decimals: 0,
|
min_decimals: 0,
|
||||||
max_decimals: None,
|
max_decimals: None,
|
||||||
|
custom_formatter: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +247,25 @@ impl<'a> Slider<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set custom formatter defining how numbers are converted into text.
|
||||||
|
///
|
||||||
|
/// 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)`.
|
/// 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,
|
/// 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.
|
/// but if you want to have a slider for picking integer values in an `Slider::f64`, use this.
|
||||||
|
@ -465,15 +490,19 @@ impl<'a> Slider<'a> {
|
||||||
_ => self.current_gradient(&position_range),
|
_ => self.current_gradient(&position_range),
|
||||||
};
|
};
|
||||||
let mut value = self.get_value();
|
let mut value = self.get_value();
|
||||||
let response = ui.add(
|
let response = ui.add({
|
||||||
DragValue::new(&mut value)
|
let dv = DragValue::new(&mut value)
|
||||||
.speed(speed)
|
.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)
|
||||||
.suffix(self.suffix.clone())
|
.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() {
|
if value != self.get_value() {
|
||||||
self.set_value(value);
|
self.set_value(value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue