Add custom parser to DragValue
and Slider
, with additional support for binary, octal, and hexadecimal numbers. (#1967)
* Add `custom_parser` to `DragValue` * Add `custom_parser` to `Slider` * Add `binary_u64`, `octal_u64`, and `hexadecimal_u64` to `DragValue` * Add `binary_u64`, `octal_u64`, and `hexadecimal_u64` to `Slider` * Fix formatting and errors in docs * Update CHANGELOG.md * Fix CI errors * Replace manual number parsing with i64::from_str_radix. Add support for signed integers. * Update CHANGELOG.md * Change documentation. * Fix documentation. * Fix documentation. * Remove unnecessary links.
This commit is contained in:
parent
3142c52b94
commit
9b2c3d1026
3 changed files with 380 additions and 9 deletions
|
@ -23,6 +23,7 @@ NOTE: [`epaint`](crates/epaint/CHANGELOG.md), [`eframe`](crates/eframe/CHANGELOG
|
|||
* Added `custom_formatter` method for `Slider` and `DragValue` ([#1851](https://github.com/emilk/egui/issues/1851)).
|
||||
* Added `RawInput::has_focus` which backends can set to indicate whether the UI as a whole has the keyboard focus ([#1859](https://github.com/emilk/egui/pull/1859)).
|
||||
* Added `PointerState::button_double_clicked()` and `PointerState::button_triple_clicked()` ([#1906](https://github.com/emilk/egui/issues/1906)).
|
||||
* Added `custom_formatter`, `binary`, `octal`, and `hexadecimal` to `DragValue` and `Slider` ([#1953](https://github.com/emilk/egui/issues/1953))
|
||||
|
||||
### Changed
|
||||
* MSRV (Minimum Supported Rust Version) is now `1.61.0` ([#1846](https://github.com/emilk/egui/pull/1846)).
|
||||
|
|
|
@ -28,6 +28,7 @@ impl MonoState {
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
type NumFormatter<'a> = Box<dyn 'a + Fn(f64, RangeInclusive<usize>) -> String>;
|
||||
type NumParser<'a> = Box<dyn 'a + Fn(&str) -> Option<f64>>;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
@ -61,6 +62,7 @@ pub struct DragValue<'a> {
|
|||
min_decimals: usize,
|
||||
max_decimals: Option<usize>,
|
||||
custom_formatter: Option<NumFormatter<'a>>,
|
||||
custom_parser: Option<NumParser<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> DragValue<'a> {
|
||||
|
@ -91,6 +93,7 @@ impl<'a> DragValue<'a> {
|
|||
min_decimals: 0,
|
||||
max_decimals: None,
|
||||
custom_formatter: None,
|
||||
custom_parser: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,10 +160,35 @@ impl<'a> DragValue<'a> {
|
|||
/// 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.
|
||||
///
|
||||
/// See also: [`DragValue::custom_parser`]
|
||||
///
|
||||
/// ```
|
||||
/// # 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)));
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::DragValue::new(&mut my_i32)
|
||||
/// .clamp_range(0..=((60 * 60 * 24) - 1))
|
||||
/// .custom_formatter(|n, _| {
|
||||
/// let n = n as i32;
|
||||
/// let hours = n / (60 * 60);
|
||||
/// let mins = (n / 60) % 60;
|
||||
/// let secs = n % 60;
|
||||
/// format!("{hours:02}:{mins:02}:{secs:02}")
|
||||
/// })
|
||||
/// .custom_parser(|s| {
|
||||
/// let parts: Vec<&str> = s.split(':').collect();
|
||||
/// if parts.len() == 3 {
|
||||
/// parts[0].parse::<i32>().and_then(|h| {
|
||||
/// parts[1].parse::<i32>().and_then(|m| {
|
||||
/// parts[2].parse::<i32>().map(|s| {
|
||||
/// ((h * 60 * 60) + (m * 60) + s) as f64
|
||||
/// })
|
||||
/// })
|
||||
/// })
|
||||
/// .ok()
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// }));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn custom_formatter(
|
||||
|
@ -170,6 +198,160 @@ impl<'a> DragValue<'a> {
|
|||
self.custom_formatter = Some(Box::new(formatter));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set custom parser defining how the text input is parsed into a number.
|
||||
///
|
||||
/// A custom parser takes an `&str` to parse into a number and returns a `f64` if it was successfully parsed
|
||||
/// or `None` otherwise.
|
||||
///
|
||||
/// See also: [`DragValue::custom_formatter`]
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::DragValue::new(&mut my_i32)
|
||||
/// .clamp_range(0..=((60 * 60 * 24) - 1))
|
||||
/// .custom_formatter(|n, _| {
|
||||
/// let n = n as i32;
|
||||
/// let hours = n / (60 * 60);
|
||||
/// let mins = (n / 60) % 60;
|
||||
/// let secs = n % 60;
|
||||
/// format!("{hours:02}:{mins:02}:{secs:02}")
|
||||
/// })
|
||||
/// .custom_parser(|s| {
|
||||
/// let parts: Vec<&str> = s.split(':').collect();
|
||||
/// if parts.len() == 3 {
|
||||
/// parts[0].parse::<i32>().and_then(|h| {
|
||||
/// parts[1].parse::<i32>().and_then(|m| {
|
||||
/// parts[2].parse::<i32>().map(|s| {
|
||||
/// ((h * 60 * 60) + (m * 60) + s) as f64
|
||||
/// })
|
||||
/// })
|
||||
/// })
|
||||
/// .ok()
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// }));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn custom_parser(mut self, parser: impl 'a + Fn(&str) -> Option<f64>) -> Self {
|
||||
self.custom_parser = Some(Box::new(parser));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set `custom_formatter` and `custom_parser` to display and parse numbers as binary integers. Floating point
|
||||
/// numbers are *not* supported.
|
||||
///
|
||||
/// `min_width` specifies the minimum number of displayed digits; if the number is shorter than this, it will be
|
||||
/// prefixed with additional 0s to match `min_width`.
|
||||
///
|
||||
/// If `twos_complement` is true, negative values will be displayed as the 2's complement representation. Otherwise
|
||||
/// they will be prefixed with a '-' sign.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `min_width` is 0.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::DragValue::new(&mut my_i32).binary(64, false));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn binary(self, min_width: usize, twos_complement: bool) -> Self {
|
||||
assert!(
|
||||
min_width > 0,
|
||||
"DragValue::binary: `min_width` must be greater than 0"
|
||||
);
|
||||
if twos_complement {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$b}", n as i64))
|
||||
} else {
|
||||
self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$b}", n.abs() as i64)
|
||||
})
|
||||
}
|
||||
.custom_parser(|s| i64::from_str_radix(s, 2).map(|n| n as f64).ok())
|
||||
}
|
||||
|
||||
/// Set `custom_formatter` and `custom_parser` to display and parse numbers as octal integers. Floating point
|
||||
/// numbers are *not* supported.
|
||||
///
|
||||
/// `min_width` specifies the minimum number of displayed digits; if the number is shorter than this, it will be
|
||||
/// prefixed with additional 0s to match `min_width`.
|
||||
///
|
||||
/// If `twos_complement` is true, negative values will be displayed as the 2's complement representation. Otherwise
|
||||
/// they will be prefixed with a '-' sign.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `min_width` is 0.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::DragValue::new(&mut my_i32).octal(22, false));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn octal(self, min_width: usize, twos_complement: bool) -> Self {
|
||||
assert!(
|
||||
min_width > 0,
|
||||
"DragValue::octal: `min_width` must be greater than 0"
|
||||
);
|
||||
if twos_complement {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$o}", n as i64))
|
||||
} else {
|
||||
self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$o}", n.abs() as i64)
|
||||
})
|
||||
}
|
||||
.custom_parser(|s| i64::from_str_radix(s, 8).map(|n| n as f64).ok())
|
||||
}
|
||||
|
||||
/// Set `custom_formatter` and `custom_parser` to display and parse numbers as hexadecimal integers. Floating point
|
||||
/// numbers are *not* supported.
|
||||
///
|
||||
/// `min_width` specifies the minimum number of displayed digits; if the number is shorter than this, it will be
|
||||
/// prefixed with additional 0s to match `min_width`.
|
||||
///
|
||||
/// If `twos_complement` is true, negative values will be displayed as the 2's complement representation. Otherwise
|
||||
/// they will be prefixed with a '-' sign.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `min_width` is 0.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::DragValue::new(&mut my_i32).hexadecimal(16, false, true));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn hexadecimal(self, min_width: usize, twos_complement: bool, upper: bool) -> Self {
|
||||
assert!(
|
||||
min_width > 0,
|
||||
"DragValue::hexadecimal: `min_width` must be greater than 0"
|
||||
);
|
||||
match (twos_complement, upper) {
|
||||
(true, true) => {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$X}", n as i64))
|
||||
}
|
||||
(true, false) => {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$x}", n as i64))
|
||||
}
|
||||
(false, true) => self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$X}", n.abs() as i64)
|
||||
}),
|
||||
(false, false) => self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$x}", n.abs() as i64)
|
||||
}),
|
||||
}
|
||||
.custom_parser(|s| i64::from_str_radix(s, 16).map(|n| n as f64).ok())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for DragValue<'a> {
|
||||
|
@ -183,6 +365,7 @@ impl<'a> Widget for DragValue<'a> {
|
|||
min_decimals,
|
||||
max_decimals,
|
||||
custom_formatter,
|
||||
custom_parser,
|
||||
} = self;
|
||||
|
||||
let shift = ui.input().modifiers.shift_only();
|
||||
|
@ -228,7 +411,11 @@ impl<'a> Widget for DragValue<'a> {
|
|||
.desired_width(button_width)
|
||||
.font(TextStyle::Monospace),
|
||||
);
|
||||
if let Ok(parsed_value) = value_text.parse() {
|
||||
let parsed_value = match custom_parser {
|
||||
Some(parser) => parser(&value_text),
|
||||
None => value_text.parse().ok(),
|
||||
};
|
||||
if let Some(parsed_value) = parsed_value {
|
||||
let parsed_value = clamp_to_range(parsed_value, clamp_range);
|
||||
set(&mut get_set_value, parsed_value);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::*;
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
type NumFormatter<'a> = Box<dyn 'a + Fn(f64, RangeInclusive<usize>) -> String>;
|
||||
type NumParser<'a> = Box<dyn 'a + Fn(&str) -> Option<f64>>;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
@ -82,6 +83,7 @@ pub struct Slider<'a> {
|
|||
min_decimals: usize,
|
||||
max_decimals: Option<usize>,
|
||||
custom_formatter: Option<NumFormatter<'a>>,
|
||||
custom_parser: Option<NumParser<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Slider<'a> {
|
||||
|
@ -126,6 +128,7 @@ impl<'a> Slider<'a> {
|
|||
min_decimals: 0,
|
||||
max_decimals: None,
|
||||
custom_formatter: None,
|
||||
custom_parser: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,10 +257,34 @@ impl<'a> Slider<'a> {
|
|||
/// 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.
|
||||
///
|
||||
/// See also: [`DragValue::custom_parser`]
|
||||
///
|
||||
/// ```
|
||||
/// # 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)));
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::Slider::new(&mut my_i32, 0..=((60 * 60 * 24) - 1))
|
||||
/// .custom_formatter(|n, _| {
|
||||
/// let n = n as i32;
|
||||
/// let hours = n / (60 * 60);
|
||||
/// let mins = (n / 60) % 60;
|
||||
/// let secs = n % 60;
|
||||
/// format!("{hours:02}:{mins:02}:{secs:02}")
|
||||
/// })
|
||||
/// .custom_parser(|s| {
|
||||
/// let parts: Vec<&str> = s.split(':').collect();
|
||||
/// if parts.len() == 3 {
|
||||
/// parts[0].parse::<i32>().and_then(|h| {
|
||||
/// parts[1].parse::<i32>().and_then(|m| {
|
||||
/// parts[2].parse::<i32>().map(|s| {
|
||||
/// ((h * 60 * 60) + (m * 60) + s) as f64
|
||||
/// })
|
||||
/// })
|
||||
/// })
|
||||
/// .ok()
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// }));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn custom_formatter(
|
||||
|
@ -268,6 +295,159 @@ impl<'a> Slider<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set custom parser defining how the text input is parsed into a number.
|
||||
///
|
||||
/// A custom parser takes an `&str` to parse into a number and returns `Some` if it was successfully parsed
|
||||
/// or `None` otherwise.
|
||||
///
|
||||
/// See also: [`DragValue::custom_formatter`]
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::Slider::new(&mut my_i32, 0..=((60 * 60 * 24) - 1))
|
||||
/// .custom_formatter(|n, _| {
|
||||
/// let n = n as i32;
|
||||
/// let hours = n / (60 * 60);
|
||||
/// let mins = (n / 60) % 60;
|
||||
/// let secs = n % 60;
|
||||
/// format!("{hours:02}:{mins:02}:{secs:02}")
|
||||
/// })
|
||||
/// .custom_parser(|s| {
|
||||
/// let parts: Vec<&str> = s.split(':').collect();
|
||||
/// if parts.len() == 3 {
|
||||
/// parts[0].parse::<i32>().and_then(|h| {
|
||||
/// parts[1].parse::<i32>().and_then(|m| {
|
||||
/// parts[2].parse::<i32>().map(|s| {
|
||||
/// ((h * 60 * 60) + (m * 60) + s) as f64
|
||||
/// })
|
||||
/// })
|
||||
/// })
|
||||
/// .ok()
|
||||
/// } else {
|
||||
/// None
|
||||
/// }
|
||||
/// }));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn custom_parser(mut self, parser: impl 'a + Fn(&str) -> Option<f64>) -> Self {
|
||||
self.custom_parser = Some(Box::new(parser));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set `custom_formatter` and `custom_parser` to display and parse numbers as binary integers. Floating point
|
||||
/// numbers are *not* supported.
|
||||
///
|
||||
/// `min_width` specifies the minimum number of displayed digits; if the number is shorter than this, it will be
|
||||
/// prefixed with additional 0s to match `min_width`.
|
||||
///
|
||||
/// If `twos_complement` is true, negative values will be displayed as the 2's complement representation. Otherwise
|
||||
/// they will be prefixed with a '-' sign.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `min_width` is 0.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::Slider::new(&mut my_i32, -100..=100).binary(64, false));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn binary(self, min_width: usize, twos_complement: bool) -> Self {
|
||||
assert!(
|
||||
min_width > 0,
|
||||
"Slider::binary: `min_width` must be greater than 0"
|
||||
);
|
||||
if twos_complement {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$b}", n as i64))
|
||||
} else {
|
||||
self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$b}", n.abs() as i64)
|
||||
})
|
||||
}
|
||||
.custom_parser(|s| i64::from_str_radix(s, 2).map(|n| n as f64).ok())
|
||||
}
|
||||
|
||||
/// Set `custom_formatter` and `custom_parser` to display and parse numbers as octal integers. Floating point
|
||||
/// numbers are *not* supported.
|
||||
///
|
||||
/// `min_width` specifies the minimum number of displayed digits; if the number is shorter than this, it will be
|
||||
/// prefixed with additional 0s to match `min_width`.
|
||||
///
|
||||
/// If `twos_complement` is true, negative values will be displayed as the 2's complement representation. Otherwise
|
||||
/// they will be prefixed with a '-' sign.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `min_width` is 0.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::Slider::new(&mut my_i32, -100..=100).octal(22, false));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn octal(self, min_width: usize, twos_complement: bool) -> Self {
|
||||
assert!(
|
||||
min_width > 0,
|
||||
"Slider::octal: `min_width` must be greater than 0"
|
||||
);
|
||||
if twos_complement {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$o}", n as i64))
|
||||
} else {
|
||||
self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$o}", n.abs() as i64)
|
||||
})
|
||||
}
|
||||
.custom_parser(|s| i64::from_str_radix(s, 8).map(|n| n as f64).ok())
|
||||
}
|
||||
|
||||
/// Set `custom_formatter` and `custom_parser` to display and parse numbers as hexadecimal integers. Floating point
|
||||
/// numbers are *not* supported.
|
||||
///
|
||||
/// `min_width` specifies the minimum number of displayed digits; if the number is shorter than this, it will be
|
||||
/// prefixed with additional 0s to match `min_width`.
|
||||
///
|
||||
/// If `twos_complement` is true, negative values will be displayed as the 2's complement representation. Otherwise
|
||||
/// they will be prefixed with a '-' sign.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `min_width` is 0.
|
||||
///
|
||||
/// ```
|
||||
/// # egui::__run_test_ui(|ui| {
|
||||
/// # let mut my_i32: i32 = 0;
|
||||
/// ui.add(egui::Slider::new(&mut my_i32, -100..=100).hexadecimal(16, false, true));
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn hexadecimal(self, min_width: usize, twos_complement: bool, upper: bool) -> Self {
|
||||
assert!(
|
||||
min_width > 0,
|
||||
"Slider::hexadecimal: `min_width` must be greater than 0"
|
||||
);
|
||||
match (twos_complement, upper) {
|
||||
(true, true) => {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$X}", n as i64))
|
||||
}
|
||||
(true, false) => {
|
||||
self.custom_formatter(move |n, _| format!("{:0>min_width$x}", n as i64))
|
||||
}
|
||||
(false, true) => self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$X}", n.abs() as i64)
|
||||
}),
|
||||
(false, false) => self.custom_formatter(move |n, _| {
|
||||
let sign = if n < 0.0 { "-" } else { "" };
|
||||
format!("{sign}{:0>min_width$x}", n.abs() as i64)
|
||||
}),
|
||||
}
|
||||
.custom_parser(|s| i64::from_str_radix(s, 16).map(|n| n as f64).ok())
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
@ -493,17 +673,20 @@ impl<'a> Slider<'a> {
|
|||
};
|
||||
let mut value = self.get_value();
|
||||
let response = ui.add({
|
||||
let dv = DragValue::new(&mut value)
|
||||
let mut 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());
|
||||
match &self.custom_formatter {
|
||||
Some(fmt) => dv.custom_formatter(fmt),
|
||||
None => dv,
|
||||
if let Some(fmt) = &self.custom_formatter {
|
||||
dv = dv.custom_formatter(fmt);
|
||||
};
|
||||
if let Some(parser) = &self.custom_parser {
|
||||
dv = dv.custom_parser(parser);
|
||||
}
|
||||
dv
|
||||
});
|
||||
if value != self.get_value() {
|
||||
self.set_value(value);
|
||||
|
|
Loading…
Reference in a new issue