whiskers_widgets/
numeric.rs

1use egui::emath::Numeric;
2
3/// A widget for built-in numeric values.
4///
5/// This widget piggybacks on the [`Numeric`] trait for its implementation.
6#[derive(Default)]
7pub struct NumericWidget<T: Numeric> {
8    min: Option<T>,
9    max: Option<T>,
10    step: Option<T>,
11    slider: bool,
12    logarithmic: bool,
13}
14
15impl<T: Numeric> NumericWidget<T> {
16    /// Sets the minimum value for the widget.
17    #[must_use]
18    pub fn min(mut self, min: T) -> Self {
19        self.min = Some(min);
20        self
21    }
22
23    /// Sets the maximum value for the widget.
24    #[must_use]
25    pub fn max(mut self, max: T) -> Self {
26        self.max = Some(max);
27        self
28    }
29
30    /// Sets the step value for the widget.
31    ///
32    /// This parameter is passed to [`egui::DragValue::speed`] in normal mode, and
33    /// [`egui::Slider::step_by`] in slider mode.
34    #[must_use]
35    pub fn step(mut self, step: T) -> Self {
36        self.step = Some(step);
37        self
38    }
39
40    /// Sets whether the widget should be displayed as a slider or not.
41    #[must_use]
42    pub fn slider(mut self, slider: bool) -> Self {
43        self.slider = slider;
44        self
45    }
46
47    /// Sets the widget to logarithmic mode. Implies [`slider(true)`].
48    #[must_use]
49    pub fn logarithmic(mut self, log: bool) -> Self {
50        self.logarithmic = log;
51        if log {
52            self.slider = true;
53        }
54        self
55    }
56}
57
58impl<T: Numeric> super::Widget<T> for NumericWidget<T> {
59    fn ui(&self, ui: &mut egui::Ui, label: &str, value: &mut T) -> bool {
60        ui.add(egui::Label::new(label));
61        let range = self.min.unwrap_or(T::MIN)..=self.max.unwrap_or(T::MAX);
62        if self.slider {
63            let mut slider = egui::Slider::new(value, range);
64            if let Some(step) = self.step {
65                slider = slider.step_by(step.to_f64());
66            }
67            if self.logarithmic {
68                slider = slider.logarithmic(true);
69            }
70            ui.add(slider).changed()
71        } else {
72            let mut drag_value = egui::DragValue::new(value).clamp_range(range);
73            if let Some(step) = self.step {
74                drag_value = drag_value.speed(step.to_f64());
75            }
76            ui.add(drag_value).changed()
77        }
78    }
79}
80
81crate::register_widget_ui!(f32, NumericWidget<f32>);
82crate::register_widget_ui!(f64, NumericWidget<f64>);
83crate::register_widget_ui!(i8, NumericWidget<i8>);
84crate::register_widget_ui!(u8, NumericWidget<u8>);
85crate::register_widget_ui!(i16, NumericWidget<i16>);
86crate::register_widget_ui!(u16, NumericWidget<u16>);
87crate::register_widget_ui!(i32, NumericWidget<i32>);
88crate::register_widget_ui!(u32, NumericWidget<u32>);
89crate::register_widget_ui!(i64, NumericWidget<i64>);
90crate::register_widget_ui!(u64, NumericWidget<u64>);
91crate::register_widget_ui!(isize, NumericWidget<isize>);
92crate::register_widget_ui!(usize, NumericWidget<usize>);