dear_imgui_rs/widget/
drag.rs

1//! Drag slider widgets for numeric input
2//!
3//! Drag sliders allow users to modify numeric values by dragging with the mouse.
4//! They provide a more intuitive way to adjust values compared to text input.
5
6use std::os::raw::c_void;
7use std::ptr;
8
9use crate::Ui;
10use crate::internal::DataTypeKind;
11use crate::sys;
12use crate::widget::slider::SliderFlags;
13
14impl Ui {
15    /// Creates a new drag slider widget. Returns true if the value has been edited.
16    pub fn drag<T: AsRef<str>, K: DataTypeKind>(&self, label: T, value: &mut K) -> bool {
17        Drag::new(label).build(self, value)
18    }
19
20    /// Creates a new unbuilt Drag.
21    pub fn drag_config<T: AsRef<str>, K: DataTypeKind>(&self, label: T) -> Drag<K, T> {
22        Drag::new(label)
23    }
24
25    /// Creates a drag float2 slider (2 floats)
26    #[doc(alias = "DragFloat2")]
27    pub fn drag_float2(&self, label: impl AsRef<str>, values: &mut [f32; 2]) -> bool {
28        unsafe {
29            let label_cstr = self.scratch_txt(label);
30            sys::igDragFloat2(
31                label_cstr,
32                values.as_mut_ptr(),
33                1.0,
34                0.0,
35                0.0,
36                ptr::null(),
37                0,
38            )
39        }
40    }
41
42    /// Creates a drag float3 slider (3 floats)
43    #[doc(alias = "DragFloat3")]
44    pub fn drag_float3(&self, label: impl AsRef<str>, values: &mut [f32; 3]) -> bool {
45        unsafe {
46            let label_cstr = self.scratch_txt(label);
47            sys::igDragFloat3(
48                label_cstr,
49                values.as_mut_ptr(),
50                1.0,
51                0.0,
52                0.0,
53                ptr::null(),
54                0,
55            )
56        }
57    }
58
59    /// Creates a drag float4 slider (4 floats)
60    #[doc(alias = "DragFloat4")]
61    pub fn drag_float4(&self, label: impl AsRef<str>, values: &mut [f32; 4]) -> bool {
62        unsafe {
63            let label_cstr = self.scratch_txt(label);
64            sys::igDragFloat4(
65                label_cstr,
66                values.as_mut_ptr(),
67                1.0,
68                0.0,
69                0.0,
70                ptr::null(),
71                0,
72            )
73        }
74    }
75
76    /// Creates a drag int2 slider (2 ints)
77    #[doc(alias = "DragInt2")]
78    pub fn drag_int2(&self, label: impl AsRef<str>, values: &mut [i32; 2]) -> bool {
79        unsafe {
80            let label_cstr = self.scratch_txt(label);
81            sys::igDragInt2(label_cstr, values.as_mut_ptr(), 1.0, 0, 0, ptr::null(), 0)
82        }
83    }
84
85    /// Creates a drag int3 slider (3 ints)
86    #[doc(alias = "DragInt3")]
87    pub fn drag_int3(&self, label: impl AsRef<str>, values: &mut [i32; 3]) -> bool {
88        unsafe {
89            let label_cstr = self.scratch_txt(label);
90            sys::igDragInt3(label_cstr, values.as_mut_ptr(), 1.0, 0, 0, ptr::null(), 0)
91        }
92    }
93
94    /// Creates a drag int4 slider (4 ints)
95    #[doc(alias = "DragInt4")]
96    pub fn drag_int4(&self, label: impl AsRef<str>, values: &mut [i32; 4]) -> bool {
97        unsafe {
98            let label_cstr = self.scratch_txt(label);
99            sys::igDragInt4(label_cstr, values.as_mut_ptr(), 1.0, 0, 0, ptr::null(), 0)
100        }
101    }
102}
103
104/// Builder for a drag slider widget
105#[derive(Clone, Debug)]
106#[must_use]
107pub struct Drag<T, L, F = &'static str> {
108    label: L,
109    speed: f32,
110    min: Option<T>,
111    max: Option<T>,
112    display_format: Option<F>,
113    flags: SliderFlags,
114}
115
116impl<L: AsRef<str>, T: DataTypeKind> Drag<T, L> {
117    /// Constructs a new drag slider builder
118    #[doc(alias = "DragScalar", alias = "DragScalarN")]
119    pub fn new(label: L) -> Self {
120        Drag {
121            label,
122            speed: 1.0,
123            min: None,
124            max: None,
125            display_format: None,
126            flags: SliderFlags::empty(),
127        }
128    }
129}
130
131impl<L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> Drag<T, L, F> {
132    /// Sets the range (inclusive)
133    pub fn range(mut self, min: T, max: T) -> Self {
134        self.min = Some(min);
135        self.max = Some(max);
136        self
137    }
138
139    /// Sets the value increment for a movement of one pixel
140    ///
141    /// Example: speed=0.2 means mouse needs to move 5 pixels to increase the slider value by 1
142    pub fn speed(mut self, speed: f32) -> Self {
143        self.speed = speed;
144        self
145    }
146
147    /// Sets the display format using *a C-style printf string*
148    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> Drag<T, L, F2> {
149        Drag {
150            label: self.label,
151            speed: self.speed,
152            min: self.min,
153            max: self.max,
154            display_format: Some(display_format),
155            flags: self.flags,
156        }
157    }
158
159    /// Replaces all current settings with the given flags
160    pub fn flags(mut self, flags: SliderFlags) -> Self {
161        self.flags = flags;
162        self
163    }
164
165    /// Builds a drag slider that is bound to the given value
166    ///
167    /// Returns true if the slider value was changed
168    pub fn build(self, ui: &Ui, value: &mut T) -> bool {
169        unsafe {
170            let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format);
171
172            sys::igDragScalar(
173                one,
174                T::KIND as i32,
175                value as *mut T as *mut c_void,
176                self.speed,
177                self.min
178                    .as_ref()
179                    .map(|min| min as *const T)
180                    .unwrap_or(ptr::null()) as *const c_void,
181                self.max
182                    .as_ref()
183                    .map(|max| max as *const T)
184                    .unwrap_or(ptr::null()) as *const c_void,
185                two,
186                self.flags.bits(),
187            )
188        }
189    }
190
191    /// Builds a horizontal array of multiple drag sliders attached to the given slice
192    ///
193    /// Returns true if any slider value was changed
194    pub fn build_array(self, ui: &Ui, values: &mut [T]) -> bool {
195        unsafe {
196            let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format);
197
198            sys::igDragScalarN(
199                one,
200                T::KIND as i32,
201                values.as_mut_ptr() as *mut c_void,
202                values.len() as i32,
203                self.speed,
204                self.min
205                    .as_ref()
206                    .map(|min| min as *const T)
207                    .unwrap_or(ptr::null()) as *const c_void,
208                self.max
209                    .as_ref()
210                    .map(|max| max as *const T)
211                    .unwrap_or(ptr::null()) as *const c_void,
212                two,
213                self.flags.bits(),
214            )
215        }
216    }
217}
218
219/// Builder for a drag range slider widget
220#[derive(Clone, Debug)]
221#[must_use]
222pub struct DragRange<T, L, F = &'static str, M = &'static str> {
223    label: L,
224    speed: f32,
225    min: Option<T>,
226    max: Option<T>,
227    display_format: Option<F>,
228    max_display_format: Option<M>,
229    flags: SliderFlags,
230}
231
232impl<T: DataTypeKind, L: AsRef<str>> DragRange<T, L> {
233    /// Constructs a new drag range slider builder
234    #[doc(alias = "DragIntRange2", alias = "DragFloatRange2")]
235    pub fn new(label: L) -> DragRange<T, L> {
236        DragRange {
237            label,
238            speed: 1.0,
239            min: None,
240            max: None,
241            display_format: None,
242            max_display_format: None,
243            flags: SliderFlags::NONE,
244        }
245    }
246}
247
248impl<T, L, F, M> DragRange<T, L, F, M>
249where
250    T: DataTypeKind,
251    L: AsRef<str>,
252    F: AsRef<str>,
253    M: AsRef<str>,
254{
255    /// Sets the range (inclusive)
256    pub fn range(mut self, min: T, max: T) -> Self {
257        self.min = Some(min);
258        self.max = Some(max);
259        self
260    }
261
262    /// Sets the value increment for a movement of one pixel
263    ///
264    /// Example: speed=0.2 means mouse needs to move 5 pixels to increase the slider value by 1
265    pub fn speed(mut self, speed: f32) -> Self {
266        self.speed = speed;
267        self
268    }
269
270    /// Sets the display format using *a C-style printf string*
271    pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> DragRange<T, L, F2, M> {
272        DragRange {
273            label: self.label,
274            speed: self.speed,
275            min: self.min,
276            max: self.max,
277            display_format: Some(display_format),
278            max_display_format: self.max_display_format,
279            flags: self.flags,
280        }
281    }
282
283    /// Sets the display format for the max value using *a C-style printf string*
284    pub fn max_display_format<M2: AsRef<str>>(
285        self,
286        max_display_format: M2,
287    ) -> DragRange<T, L, F, M2> {
288        DragRange {
289            label: self.label,
290            speed: self.speed,
291            min: self.min,
292            max: self.max,
293            display_format: self.display_format,
294            max_display_format: Some(max_display_format),
295            flags: self.flags,
296        }
297    }
298
299    /// Replaces all current settings with the given flags
300    pub fn flags(mut self, flags: SliderFlags) -> Self {
301        self.flags = flags;
302        self
303    }
304}
305
306impl<L, F, M> DragRange<f32, L, F, M>
307where
308    L: AsRef<str>,
309    F: AsRef<str>,
310    M: AsRef<str>,
311{
312    /// Builds a drag range slider that is bound to the given min/max values
313    ///
314    /// Returns true if the slider value was changed
315    #[doc(alias = "DragFloatRange2")]
316    pub fn build(self, ui: &Ui, min: &mut f32, max: &mut f32) -> bool {
317        unsafe {
318            let buffer = &mut *ui.scratch_buffer().get();
319            buffer.refresh_buffer();
320
321            let label_start = buffer.push(self.label);
322            let display_format = self.display_format.as_ref().map(|v| buffer.push(v));
323            let max_display_format = self.max_display_format.as_ref().map(|v| buffer.push(v));
324
325            let label = buffer.offset(label_start);
326            let display_format = display_format
327                .map(|v| buffer.offset(v))
328                .unwrap_or_else(std::ptr::null);
329            let max_display_format = max_display_format
330                .map(|v| buffer.offset(v))
331                .unwrap_or_else(std::ptr::null);
332
333            sys::igDragFloatRange2(
334                label,
335                min as *mut f32,
336                max as *mut f32,
337                self.speed,
338                self.min.unwrap_or(0.0),
339                self.max.unwrap_or(0.0),
340                display_format,
341                max_display_format,
342                self.flags.bits(),
343            )
344        }
345    }
346}
347
348impl<L, F, M> DragRange<i32, L, F, M>
349where
350    L: AsRef<str>,
351    F: AsRef<str>,
352    M: AsRef<str>,
353{
354    /// Builds a drag range slider that is bound to the given min/max values
355    ///
356    /// Returns true if the slider value was changed
357    #[doc(alias = "DragIntRange2")]
358    pub fn build(self, ui: &Ui, min: &mut i32, max: &mut i32) -> bool {
359        unsafe {
360            let buffer = &mut *ui.scratch_buffer().get();
361            buffer.refresh_buffer();
362
363            let label_start = buffer.push(self.label);
364            let display_format = self.display_format.as_ref().map(|v| buffer.push(v));
365            let max_display_format = self.max_display_format.as_ref().map(|v| buffer.push(v));
366
367            let label = buffer.offset(label_start);
368            let display_format = display_format
369                .map(|v| buffer.offset(v))
370                .unwrap_or_else(std::ptr::null);
371            let max_display_format = max_display_format
372                .map(|v| buffer.offset(v))
373                .unwrap_or_else(std::ptr::null);
374
375            sys::igDragIntRange2(
376                label,
377                min as *mut i32,
378                max as *mut i32,
379                self.speed,
380                self.min.unwrap_or(0),
381                self.max.unwrap_or(0),
382                display_format,
383                max_display_format,
384                self.flags.bits(),
385            )
386        }
387    }
388}