arcdps_imgui\widget/
slider.rs

1use bitflags::bitflags;
2use std::os::raw::c_void;
3
4use crate::internal::DataTypeKind;
5use crate::sys;
6use crate::Ui;
7
8bitflags!(
9    /// Flags for sliders
10    #[repr(transparent)]
11    pub struct SliderFlags: u32 {
12        /// Clamp value to min/max bounds when input manually with CTRL+Click.
13        ///
14        /// By default CTRL+click allows going out of bounds.
15        const ALWAYS_CLAMP = sys::ImGuiSliderFlags_AlwaysClamp;
16        /// Make the widget logarithmic instead of linear
17        const LOGARITHMIC = sys::ImGuiSliderFlags_Logarithmic;
18        /// Disable rounding underlying value to match precision of the display format string
19        const NO_ROUND_TO_FORMAT = sys::ImGuiSliderFlags_NoRoundToFormat;
20        /// Disable CTRL+Click or Enter key allowing to input text directly into the widget
21        const NO_INPUT = sys::ImGuiSliderFlags_NoInput;
22    }
23);
24
25/// Builder for a slider widget.
26#[derive(Copy, Clone, Debug)]
27#[must_use]
28pub struct Slider<Label, Data, Format = &'static str> {
29    label: Label,
30    min: Data,
31    max: Data,
32    display_format: Option<Format>,
33    flags: SliderFlags,
34}
35
36impl<T: AsRef<str>, K: DataTypeKind> Slider<T, K> {
37    /// Constructs a new slider builder with the given range.
38    #[doc(alias = "SliderScalar", alias = "SliderScalarN")]
39    pub fn new(label: T, min: K, max: K) -> Self {
40        Slider {
41            label,
42            min,
43            max,
44            display_format: None,
45            flags: SliderFlags::empty(),
46        }
47    }
48}
49
50impl<Label, Data, Format> Slider<Label, Data, Format>
51where
52    Label: AsRef<str>,
53    Data: DataTypeKind,
54    Format: AsRef<str>,
55{
56    /// Sets the range inclusively, such that both values given
57    /// are valid values which the slider can be dragged to.
58    ///
59    /// ```rust
60    /// # use arcdps_imgui::im_str;
61    /// arcdps_imgui::Slider::new(im_str!("Example"), i8::MIN, i8::MAX)
62    ///     .range(4, 8)
63    ///     // Remember to call .build(&ui)
64    ///     ;
65    /// ```
66    ///
67    /// It is safe, though up to C++ Dear ImGui, on how to handle when
68    /// `min > max`.
69    #[inline]
70    pub fn range(mut self, min: Data, max: Data) -> Self {
71        self.min = min;
72        self.max = max;
73        self
74    }
75    /// Sets the display format using *a C-style printf string*
76    #[inline]
77    pub fn display_format<Format2: AsRef<str>>(
78        self,
79        display_format: Format2,
80    ) -> Slider<Label, Data, Format2> {
81        Slider {
82            label: self.label,
83            min: self.min,
84            max: self.max,
85            display_format: Some(display_format),
86            flags: self.flags,
87        }
88    }
89    /// Replaces all current settings with the given flags
90    #[inline]
91    pub fn flags(mut self, flags: SliderFlags) -> Self {
92        self.flags = flags;
93        self
94    }
95    /// Builds a slider that is bound to the given value.
96    ///
97    /// Returns true if the slider value was changed.
98    pub fn build(self, ui: &Ui<'_>, value: &mut Data) -> bool {
99        unsafe {
100            let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format);
101
102            sys::igSliderScalar(
103                label,
104                Data::KIND as i32,
105                value as *mut Data as *mut c_void,
106                &self.min as *const Data as *const c_void,
107                &self.max as *const Data as *const c_void,
108                display_format,
109                self.flags.bits() as i32,
110            )
111        }
112    }
113    /// Builds a horizontal array of multiple sliders attached to the given slice.
114    ///
115    /// Returns true if any slider value was changed.
116    pub fn build_array(self, ui: &Ui<'_>, values: &mut [Data]) -> bool {
117        unsafe {
118            let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format);
119
120            sys::igSliderScalarN(
121                label,
122                Data::KIND as i32,
123                values.as_mut_ptr() as *mut c_void,
124                values.len() as i32,
125                &self.min as *const Data as *const c_void,
126                &self.max as *const Data as *const c_void,
127                display_format,
128                self.flags.bits() as i32,
129            )
130        }
131    }
132}
133
134/// Builder for a vertical slider widget.
135#[derive(Clone, Debug)]
136#[must_use]
137pub struct VerticalSlider<Label, Data, Format = &'static str> {
138    label: Label,
139    size: [f32; 2],
140    min: Data,
141    max: Data,
142    display_format: Option<Format>,
143    flags: SliderFlags,
144}
145
146impl<Label, Data> VerticalSlider<Label, Data>
147where
148    Label: AsRef<str>,
149    Data: DataTypeKind,
150{
151    /// Constructs a new vertical slider builder with the given size and range.
152    ///
153    /// ```rust
154    /// # use arcdps_imgui::im_str;
155    /// arcdps_imgui::VerticalSlider::new(im_str!("Example"), [20.0, 20.0], i8::MIN, i8::MAX)
156    ///     .range(4, 8)
157    ///     // Remember to call .build(&ui)
158    ///     ;
159    /// ```
160    ///
161    /// It is safe, though up to C++ Dear ImGui, on how to handle when
162    /// `min > max`.
163    #[doc(alias = "VSliderScalar")]
164    pub fn new(label: Label, size: [f32; 2], min: Data, max: Data) -> Self {
165        VerticalSlider {
166            label,
167            size,
168            min,
169            max,
170            display_format: None,
171            flags: SliderFlags::empty(),
172        }
173    }
174}
175
176impl<Label, Data, Format> VerticalSlider<Label, Data, Format>
177where
178    Label: AsRef<str>,
179    Data: DataTypeKind,
180    Format: AsRef<str>,
181{
182    /// Sets the range for the vertical slider.
183    ///
184    /// ```rust
185    /// # use arcdps_imgui::im_str;
186    /// arcdps_imgui::VerticalSlider::new(im_str!("Example"), [20.0, 20.0], i8::MIN, i8::MAX)
187    ///     .range(4, 8)
188    ///     // Remember to call .build(&ui)
189    ///     ;
190    /// ```
191    ///
192    /// It is safe, though up to C++ Dear ImGui, on how to handle when
193    /// `min > max`.
194    #[inline]
195    pub fn range(mut self, min: Data, max: Data) -> Self {
196        self.min = min;
197        self.max = max;
198        self
199    }
200    /// Sets the display format using *a C-style printf string*
201    #[inline]
202    pub fn display_format<Format2: AsRef<str>>(
203        self,
204        display_format: Format2,
205    ) -> VerticalSlider<Label, Data, Format2> {
206        VerticalSlider {
207            label: self.label,
208            size: self.size,
209            min: self.min,
210            max: self.max,
211            display_format: Some(display_format),
212            flags: self.flags,
213        }
214    }
215    /// Replaces all current settings with the given flags
216    #[inline]
217    pub fn flags(mut self, flags: SliderFlags) -> Self {
218        self.flags = flags;
219        self
220    }
221    /// Builds a vertical slider that is bound to the given value.
222    ///
223    /// Returns true if the slider value was changed.
224    pub fn build(self, ui: &Ui<'_>, value: &mut Data) -> bool {
225        unsafe {
226            let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format);
227
228            sys::igVSliderScalar(
229                label,
230                self.size.into(),
231                Data::KIND as i32,
232                value as *mut Data as *mut c_void,
233                &self.min as *const Data as *const c_void,
234                &self.max as *const Data as *const c_void,
235                display_format,
236                self.flags.bits() as i32,
237            )
238        }
239    }
240}
241
242/// Builder for an angle slider widget.
243#[derive(Copy, Clone, Debug)]
244#[must_use]
245pub struct AngleSlider<Label, Format = &'static str> {
246    label: Label,
247    min_degrees: f32,
248    max_degrees: f32,
249    display_format: Format,
250    flags: SliderFlags,
251}
252
253impl<Label> AngleSlider<Label>
254where
255    Label: AsRef<str>,
256{
257    /// Constructs a new angle slider builder, where its minimum defaults to -360.0 and
258    /// maximum defaults to 360.0
259    #[doc(alias = "SliderAngle")]
260    pub fn new(label: Label) -> Self {
261        AngleSlider {
262            label,
263            min_degrees: -360.0,
264            max_degrees: 360.0,
265            display_format: "%.0f deg",
266            flags: SliderFlags::empty(),
267        }
268    }
269}
270
271impl<Label, Format> AngleSlider<Label, Format>
272where
273    Label: AsRef<str>,
274    Format: AsRef<str>,
275{
276    /// Sets the range in degrees (inclusive)
277    /// ```rust
278    /// # use arcdps_imgui::im_str;
279    /// arcdps_imgui::AngleSlider::new(im_str!("Example"))
280    ///     .range_degrees(-20.0, 20.0)
281    ///     // Remember to call .build(&ui)
282    ///     ;
283    /// ```
284    ///
285    /// It is safe, though up to C++ Dear ImGui, on how to handle when
286    /// `min > max`.
287    #[inline]
288    pub fn range_degrees(mut self, min_degrees: f32, max_degrees: f32) -> Self {
289        self.min_degrees = min_degrees;
290        self.max_degrees = max_degrees;
291        self
292    }
293    /// Sets the minimum value (in degrees)
294    #[inline]
295    pub fn min_degrees(mut self, min_degrees: f32) -> Self {
296        self.min_degrees = min_degrees;
297        self
298    }
299    /// Sets the maximum value (in degrees)
300    #[inline]
301    pub fn max_degrees(mut self, max_degrees: f32) -> Self {
302        self.max_degrees = max_degrees;
303        self
304    }
305    /// Sets the display format using *a C-style printf string*
306    #[inline]
307    pub fn display_format<Format2: AsRef<str>>(
308        self,
309        display_format: Format2,
310    ) -> AngleSlider<Label, Format2> {
311        AngleSlider {
312            label: self.label,
313            min_degrees: self.min_degrees,
314            max_degrees: self.max_degrees,
315            display_format,
316            flags: self.flags,
317        }
318    }
319    /// Replaces all current settings with the given flags
320    #[inline]
321    pub fn flags(mut self, flags: SliderFlags) -> Self {
322        self.flags = flags;
323        self
324    }
325    /// Builds an angle slider that is bound to the given value (in radians).
326    ///
327    /// Returns true if the slider value was changed.
328    pub fn build(self, ui: &Ui<'_>, value_rad: &mut f32) -> bool {
329        unsafe {
330            let (label, display_format) = ui.scratch_txt_two(self.label, self.display_format);
331
332            sys::igSliderAngle(
333                label,
334                value_rad as *mut _,
335                self.min_degrees,
336                self.max_degrees,
337                display_format,
338                self.flags.bits() as i32,
339            )
340        }
341    }
342}