1use 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
14bitflags::bitflags! {
15 #[repr(transparent)]
20 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
21 pub struct DragFlags: i32 {
22 const NONE = 0;
24 const WRAP_AROUND = sys::ImGuiSliderFlags_WrapAround as i32;
26 const CLAMP_ON_INPUT = sys::ImGuiSliderFlags_ClampOnInput as i32;
28 const CLAMP_ZERO_RANGE = sys::ImGuiSliderFlags_ClampZeroRange as i32;
30 const NO_SPEED_TWEAKS = sys::ImGuiSliderFlags_NoSpeedTweaks as i32;
32 const ALWAYS_CLAMP = sys::ImGuiSliderFlags_AlwaysClamp as i32;
34 const LOGARITHMIC = sys::ImGuiSliderFlags_Logarithmic as i32;
36 const NO_ROUND_TO_FORMAT = sys::ImGuiSliderFlags_NoRoundToFormat as i32;
38 const NO_INPUT = sys::ImGuiSliderFlags_NoInput as i32;
40 }
41}
42
43impl From<SliderFlags> for DragFlags {
44 fn from(flags: SliderFlags) -> Self {
45 Self::from_bits_retain(flags.bits())
46 }
47}
48
49impl Ui {
50 pub fn drag<T: AsRef<str>, K: DataTypeKind>(&self, label: T, value: &mut K) -> bool {
52 Drag::new(label).build(self, value)
53 }
54
55 pub fn drag_config<T: AsRef<str>, K: DataTypeKind>(&self, label: T) -> Drag<K, T> {
57 Drag::new(label)
58 }
59
60 #[doc(alias = "DragFloat2")]
62 pub fn drag_float2(&self, label: impl AsRef<str>, values: &mut [f32; 2]) -> bool {
63 unsafe {
64 let label_cstr = self.scratch_txt(label);
65 sys::igDragFloat2(
66 label_cstr,
67 values.as_mut_ptr(),
68 1.0,
69 0.0,
70 0.0,
71 ptr::null(),
72 0,
73 )
74 }
75 }
76
77 #[doc(alias = "DragFloat3")]
79 pub fn drag_float3(&self, label: impl AsRef<str>, values: &mut [f32; 3]) -> bool {
80 unsafe {
81 let label_cstr = self.scratch_txt(label);
82 sys::igDragFloat3(
83 label_cstr,
84 values.as_mut_ptr(),
85 1.0,
86 0.0,
87 0.0,
88 ptr::null(),
89 0,
90 )
91 }
92 }
93
94 #[doc(alias = "DragFloat4")]
96 pub fn drag_float4(&self, label: impl AsRef<str>, values: &mut [f32; 4]) -> bool {
97 unsafe {
98 let label_cstr = self.scratch_txt(label);
99 sys::igDragFloat4(
100 label_cstr,
101 values.as_mut_ptr(),
102 1.0,
103 0.0,
104 0.0,
105 ptr::null(),
106 0,
107 )
108 }
109 }
110
111 #[doc(alias = "DragInt2")]
113 pub fn drag_int2(&self, label: impl AsRef<str>, values: &mut [i32; 2]) -> bool {
114 unsafe {
115 let label_cstr = self.scratch_txt(label);
116 sys::igDragInt2(label_cstr, values.as_mut_ptr(), 1.0, 0, 0, ptr::null(), 0)
117 }
118 }
119
120 #[doc(alias = "DragInt3")]
122 pub fn drag_int3(&self, label: impl AsRef<str>, values: &mut [i32; 3]) -> bool {
123 unsafe {
124 let label_cstr = self.scratch_txt(label);
125 sys::igDragInt3(label_cstr, values.as_mut_ptr(), 1.0, 0, 0, ptr::null(), 0)
126 }
127 }
128
129 #[doc(alias = "DragInt4")]
131 pub fn drag_int4(&self, label: impl AsRef<str>, values: &mut [i32; 4]) -> bool {
132 unsafe {
133 let label_cstr = self.scratch_txt(label);
134 sys::igDragInt4(label_cstr, values.as_mut_ptr(), 1.0, 0, 0, ptr::null(), 0)
135 }
136 }
137}
138
139#[derive(Clone, Debug)]
141#[must_use]
142pub struct Drag<T, L, F = &'static str> {
143 label: L,
144 speed: f32,
145 min: Option<T>,
146 max: Option<T>,
147 display_format: Option<F>,
148 flags: DragFlags,
149}
150
151impl<L: AsRef<str>, T: DataTypeKind> Drag<T, L> {
152 #[doc(alias = "DragScalar", alias = "DragScalarN")]
154 pub fn new(label: L) -> Self {
155 Drag {
156 label,
157 speed: 1.0,
158 min: None,
159 max: None,
160 display_format: None,
161 flags: DragFlags::empty(),
162 }
163 }
164}
165
166impl<L: AsRef<str>, T: DataTypeKind, F: AsRef<str>> Drag<T, L, F> {
167 pub fn range(mut self, min: T, max: T) -> Self {
169 self.min = Some(min);
170 self.max = Some(max);
171 self
172 }
173
174 pub fn speed(mut self, speed: f32) -> Self {
178 self.speed = speed;
179 self
180 }
181
182 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> Drag<T, L, F2> {
184 Drag {
185 label: self.label,
186 speed: self.speed,
187 min: self.min,
188 max: self.max,
189 display_format: Some(display_format),
190 flags: self.flags,
191 }
192 }
193
194 pub fn flags(mut self, flags: impl Into<DragFlags>) -> Self {
196 self.flags = flags.into();
197 self
198 }
199
200 pub fn build(self, ui: &Ui, value: &mut T) -> bool {
204 unsafe {
205 let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format);
206
207 sys::igDragScalar(
208 one,
209 T::KIND as i32,
210 value as *mut T as *mut c_void,
211 self.speed,
212 self.min
213 .as_ref()
214 .map(|min| min as *const T)
215 .unwrap_or(ptr::null()) as *const c_void,
216 self.max
217 .as_ref()
218 .map(|max| max as *const T)
219 .unwrap_or(ptr::null()) as *const c_void,
220 two,
221 self.flags.bits(),
222 )
223 }
224 }
225
226 pub fn build_array(self, ui: &Ui, values: &mut [T]) -> bool {
230 let count = match i32::try_from(values.len()) {
231 Ok(n) => n,
232 Err(_) => return false,
233 };
234 unsafe {
235 let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format);
236
237 sys::igDragScalarN(
238 one,
239 T::KIND as i32,
240 values.as_mut_ptr() as *mut c_void,
241 count,
242 self.speed,
243 self.min
244 .as_ref()
245 .map(|min| min as *const T)
246 .unwrap_or(ptr::null()) as *const c_void,
247 self.max
248 .as_ref()
249 .map(|max| max as *const T)
250 .unwrap_or(ptr::null()) as *const c_void,
251 two,
252 self.flags.bits(),
253 )
254 }
255 }
256}
257
258#[derive(Clone, Debug)]
260#[must_use]
261pub struct DragRange<T, L, F = &'static str, M = &'static str> {
262 label: L,
263 speed: f32,
264 min: Option<T>,
265 max: Option<T>,
266 display_format: Option<F>,
267 max_display_format: Option<M>,
268 flags: DragFlags,
269}
270
271impl<T: DataTypeKind, L: AsRef<str>> DragRange<T, L> {
272 #[doc(alias = "DragIntRange2", alias = "DragFloatRange2")]
274 pub fn new(label: L) -> DragRange<T, L> {
275 DragRange {
276 label,
277 speed: 1.0,
278 min: None,
279 max: None,
280 display_format: None,
281 max_display_format: None,
282 flags: DragFlags::NONE,
283 }
284 }
285}
286
287impl<T, L, F, M> DragRange<T, L, F, M>
288where
289 T: DataTypeKind,
290 L: AsRef<str>,
291 F: AsRef<str>,
292 M: AsRef<str>,
293{
294 pub fn range(mut self, min: T, max: T) -> Self {
296 self.min = Some(min);
297 self.max = Some(max);
298 self
299 }
300
301 pub fn speed(mut self, speed: f32) -> Self {
305 self.speed = speed;
306 self
307 }
308
309 pub fn display_format<F2: AsRef<str>>(self, display_format: F2) -> DragRange<T, L, F2, M> {
311 DragRange {
312 label: self.label,
313 speed: self.speed,
314 min: self.min,
315 max: self.max,
316 display_format: Some(display_format),
317 max_display_format: self.max_display_format,
318 flags: self.flags,
319 }
320 }
321
322 pub fn max_display_format<M2: AsRef<str>>(
324 self,
325 max_display_format: M2,
326 ) -> DragRange<T, L, F, M2> {
327 DragRange {
328 label: self.label,
329 speed: self.speed,
330 min: self.min,
331 max: self.max,
332 display_format: self.display_format,
333 max_display_format: Some(max_display_format),
334 flags: self.flags,
335 }
336 }
337
338 pub fn flags(mut self, flags: impl Into<DragFlags>) -> Self {
340 self.flags = flags.into();
341 self
342 }
343}
344
345impl<L, F, M> DragRange<f32, L, F, M>
346where
347 L: AsRef<str>,
348 F: AsRef<str>,
349 M: AsRef<str>,
350{
351 #[doc(alias = "DragFloatRange2")]
355 pub fn build(self, ui: &Ui, min: &mut f32, max: &mut f32) -> bool {
356 unsafe {
357 let buffer = &mut *ui.scratch_buffer().get();
358 buffer.refresh_buffer();
359
360 let label_start = buffer.push(self.label);
361 let display_format = self.display_format.as_ref().map(|v| buffer.push(v));
362 let max_display_format = self.max_display_format.as_ref().map(|v| buffer.push(v));
363
364 let label = buffer.offset(label_start);
365 let display_format = display_format
366 .map(|v| buffer.offset(v))
367 .unwrap_or_else(std::ptr::null);
368 let max_display_format = max_display_format
369 .map(|v| buffer.offset(v))
370 .unwrap_or_else(std::ptr::null);
371
372 sys::igDragFloatRange2(
373 label,
374 min as *mut f32,
375 max as *mut f32,
376 self.speed,
377 self.min.unwrap_or(0.0),
378 self.max.unwrap_or(0.0),
379 display_format,
380 max_display_format,
381 self.flags.bits(),
382 )
383 }
384 }
385}
386
387impl<L, F, M> DragRange<i32, L, F, M>
388where
389 L: AsRef<str>,
390 F: AsRef<str>,
391 M: AsRef<str>,
392{
393 #[doc(alias = "DragIntRange2")]
397 pub fn build(self, ui: &Ui, min: &mut i32, max: &mut i32) -> bool {
398 unsafe {
399 let buffer = &mut *ui.scratch_buffer().get();
400 buffer.refresh_buffer();
401
402 let label_start = buffer.push(self.label);
403 let display_format = self.display_format.as_ref().map(|v| buffer.push(v));
404 let max_display_format = self.max_display_format.as_ref().map(|v| buffer.push(v));
405
406 let label = buffer.offset(label_start);
407 let display_format = display_format
408 .map(|v| buffer.offset(v))
409 .unwrap_or_else(std::ptr::null);
410 let max_display_format = max_display_format
411 .map(|v| buffer.offset(v))
412 .unwrap_or_else(std::ptr::null);
413
414 sys::igDragIntRange2(
415 label,
416 min as *mut i32,
417 max as *mut i32,
418 self.speed,
419 self.min.unwrap_or(0),
420 self.max.unwrap_or(0),
421 display_format,
422 max_display_format,
423 self.flags.bits(),
424 )
425 }
426 }
427}