dear_imgui/
draw.rs

1#![allow(
2    clippy::cast_possible_truncation,
3    clippy::cast_sign_loss,
4    clippy::as_conversions,
5    clippy::unnecessary_cast
6)]
7use crate::texture::TextureId;
8use bitflags::bitflags;
9use std::marker::PhantomData;
10
11use crate::colors::Color;
12use crate::sys;
13
14// (MintVec2 legacy alias removed; draw APIs now accept Into<sys::ImVec2>)
15
16/// Packed RGBA color compatible with imgui-rs
17#[repr(transparent)]
18#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
19pub struct ImColor32(u32);
20
21impl ImColor32 {
22    /// Convenience constant for solid black.
23    pub const BLACK: Self = Self(0xff_00_00_00);
24    /// Convenience constant for solid white.
25    pub const WHITE: Self = Self(0xff_ff_ff_ff);
26    /// Convenience constant for full transparency.
27    pub const TRANSPARENT: Self = Self(0);
28
29    /// Construct a color from 4 single-byte `u8` channel values
30    #[inline]
31    pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
32        Self(((a as u32) << 24) | (r as u32) | ((g as u32) << 8) | ((b as u32) << 16))
33    }
34
35    /// Construct a fully opaque color from 3 single-byte `u8` channel values
36    #[inline]
37    pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
38        Self::from_rgba(r, g, b, 0xff)
39    }
40
41    /// Construct from f32 values in range 0.0..=1.0
42    pub fn from_rgba_f32s(r: f32, g: f32, b: f32, a: f32) -> Self {
43        Self::from_rgba(
44            (r.clamp(0.0, 1.0) * 255.0) as u8,
45            (g.clamp(0.0, 1.0) * 255.0) as u8,
46            (b.clamp(0.0, 1.0) * 255.0) as u8,
47            (a.clamp(0.0, 1.0) * 255.0) as u8,
48        )
49    }
50
51    /// Return the bits of the color as a u32
52    #[inline]
53    pub const fn to_bits(self) -> u32 {
54        self.0
55    }
56}
57
58impl From<Color> for ImColor32 {
59    fn from(color: Color) -> Self {
60        Self::from_rgba_f32s(color.r, color.g, color.b, color.a)
61    }
62}
63
64impl From<[f32; 4]> for ImColor32 {
65    fn from(arr: [f32; 4]) -> Self {
66        Self::from_rgba_f32s(arr[0], arr[1], arr[2], arr[3])
67    }
68}
69
70impl From<(f32, f32, f32, f32)> for ImColor32 {
71    fn from((r, g, b, a): (f32, f32, f32, f32)) -> Self {
72        Self::from_rgba_f32s(r, g, b, a)
73    }
74}
75
76impl From<[f32; 3]> for ImColor32 {
77    fn from(arr: [f32; 3]) -> Self {
78        Self::from_rgba_f32s(arr[0], arr[1], arr[2], 1.0)
79    }
80}
81
82impl From<(f32, f32, f32)> for ImColor32 {
83    fn from((r, g, b): (f32, f32, f32)) -> Self {
84        Self::from_rgba_f32s(r, g, b, 1.0)
85    }
86}
87
88impl From<ImColor32> for u32 {
89    fn from(color: ImColor32) -> Self {
90        color.0
91    }
92}
93
94impl From<u32> for ImColor32 {
95    fn from(color: u32) -> Self {
96        ImColor32(color)
97    }
98}
99
100// Removed legacy local Vec2 in favor of passing `impl Into<sys::ImVec2>` and using arrays/tuples.
101bitflags! {
102    /// Draw list flags
103    #[repr(transparent)]
104    pub struct DrawListFlags: i32 {
105        /// No flags
106        const NONE = sys::ImDrawListFlags_None as i32;
107        /// Enable anti-aliased lines/borders
108        const ANTI_ALIASED_LINES = sys::ImDrawListFlags_AntiAliasedLines as i32;
109        /// Enable anti-aliased lines/borders using textures where possible
110        const ANTI_ALIASED_LINES_USE_TEX = sys::ImDrawListFlags_AntiAliasedLinesUseTex as i32;
111        /// Enable anti-aliased edge around filled shapes
112        const ANTI_ALIASED_FILL = sys::ImDrawListFlags_AntiAliasedFill as i32;
113        /// Can emit 'VtxOffset > 0' to allow large meshes
114        const ALLOW_VTX_OFFSET = sys::ImDrawListFlags_AllowVtxOffset as i32;
115    }
116}
117
118bitflags! {
119    /// Options for some DrawList operations
120    /// Values mirror ImGui's `ImDrawFlags_*` (v1.92+).
121    #[repr(transparent)]
122    pub struct DrawFlags: u32 {
123        const NONE = sys::ImDrawFlags_None as u32;
124        const CLOSED = sys::ImDrawFlags_Closed as u32;
125        const ROUND_CORNERS_TOP_LEFT = sys::ImDrawFlags_RoundCornersTopLeft as u32;
126        const ROUND_CORNERS_TOP_RIGHT = sys::ImDrawFlags_RoundCornersTopRight as u32;
127        const ROUND_CORNERS_BOT_LEFT = sys::ImDrawFlags_RoundCornersBottomLeft as u32;
128        const ROUND_CORNERS_BOT_RIGHT = sys::ImDrawFlags_RoundCornersBottomRight as u32;
129        const ROUND_CORNERS_TOP = sys::ImDrawFlags_RoundCornersTop as u32;
130        const ROUND_CORNERS_BOT = sys::ImDrawFlags_RoundCornersBottom as u32;
131        const ROUND_CORNERS_LEFT = sys::ImDrawFlags_RoundCornersLeft as u32;
132        const ROUND_CORNERS_RIGHT = sys::ImDrawFlags_RoundCornersRight as u32;
133        const ROUND_CORNERS_ALL = sys::ImDrawFlags_RoundCornersAll as u32;
134        const ROUND_CORNERS_NONE = sys::ImDrawFlags_RoundCornersNone as u32;
135    }
136}
137
138// All draw types have been moved to crate::render module
139// Use crate::render::{DrawVert, DrawIdx, DrawData, DrawListIterator} instead
140
141/// Draw list wrapper
142#[repr(transparent)]
143pub struct DrawList(*mut sys::ImDrawList);
144
145impl DrawList {
146    /// Create DrawList from raw pointer (crate-internal)
147    ///
148    /// Safety: caller must ensure pointer validity for returned lifetime.
149    pub(crate) unsafe fn from_raw(ptr: *mut sys::ImDrawList) -> Self {
150        Self(ptr)
151    }
152
153    /// Get command buffer as slice
154    unsafe fn cmd_buffer(&self) -> &[sys::ImDrawCmd] {
155        unsafe {
156            if (*self.0).CmdBuffer.Size <= 0 || (*self.0).CmdBuffer.Data.is_null() {
157                return &[];
158            }
159            std::slice::from_raw_parts(
160                (*self.0).CmdBuffer.Data as *const sys::ImDrawCmd,
161                (*self.0).CmdBuffer.Size as usize,
162            )
163        }
164    }
165
166    /// Get vertex buffer
167    pub fn vtx_buffer(&self) -> &[crate::render::DrawVert] {
168        unsafe {
169            if (*self.0).VtxBuffer.Size <= 0 || (*self.0).VtxBuffer.Data.is_null() {
170                return &[];
171            }
172            std::slice::from_raw_parts(
173                (*self.0).VtxBuffer.Data as *const crate::render::DrawVert,
174                (*self.0).VtxBuffer.Size as usize,
175            )
176        }
177    }
178
179    /// Get index buffer
180    pub fn idx_buffer(&self) -> &[crate::render::DrawIdx] {
181        unsafe {
182            if (*self.0).IdxBuffer.Size <= 0 || (*self.0).IdxBuffer.Data.is_null() {
183                return &[];
184            }
185            std::slice::from_raw_parts((*self.0).IdxBuffer.Data, (*self.0).IdxBuffer.Size as usize)
186        }
187    }
188
189    /// Get draw commands iterator
190    pub fn commands(&self) -> DrawCmdIterator<'_> {
191        unsafe {
192            DrawCmdIterator {
193                iter: self.cmd_buffer().iter(),
194            }
195        }
196    }
197}
198
199/// Owned draw list returned by `CloneOutput`.
200///
201/// This owns an independent copy of a draw list and will free it on drop.
202pub struct OwnedDrawList(*mut sys::ImDrawList);
203
204impl Drop for OwnedDrawList {
205    fn drop(&mut self) {
206        unsafe { sys::ImDrawList_destroy(self.0) }
207    }
208}
209
210impl OwnedDrawList {
211    /// Create from raw pointer.
212    ///
213    /// Safety: `ptr` must be a valid pointer returned by `ImDrawList_CloneOutput` or `ImDrawList_ImDrawList`.
214    pub(crate) unsafe fn from_raw(ptr: *mut sys::ImDrawList) -> Self {
215        Self(ptr)
216    }
217
218    /// Borrow as a read-only draw list view.
219    pub fn as_view(&self) -> DrawList {
220        DrawList(self.0)
221    }
222
223    /// Clear free memory held by the draw list (release heap allocations).
224    pub fn clear_free_memory(&mut self) {
225        unsafe { sys::ImDrawList__ClearFreeMemory(self.0) }
226    }
227
228    /// Reset for new frame (not commonly needed for cloned lists).
229    pub fn reset_for_new_frame(&mut self) {
230        unsafe { sys::ImDrawList__ResetForNewFrame(self.0) }
231    }
232}
233
234/// Iterator over draw commands
235pub struct DrawCmdIterator<'a> {
236    iter: std::slice::Iter<'a, sys::ImDrawCmd>,
237}
238
239impl Iterator for DrawCmdIterator<'_> {
240    type Item = DrawCmd;
241
242    fn next(&mut self) -> Option<Self::Item> {
243        self.iter.next().map(|cmd| {
244            let cmd_params = DrawCmdParams {
245                clip_rect: [
246                    cmd.ClipRect.x,
247                    cmd.ClipRect.y,
248                    cmd.ClipRect.z,
249                    cmd.ClipRect.w,
250                ],
251                texture_id: TextureId::from(unsafe {
252                    sys::ImDrawCmd_GetTexID(cmd as *const _ as *mut sys::ImDrawCmd)
253                }),
254                vtx_offset: cmd.VtxOffset as usize,
255                idx_offset: cmd.IdxOffset as usize,
256            };
257
258            match cmd.UserCallback {
259                Some(raw_callback) if raw_callback as usize == usize::MAX => {
260                    DrawCmd::ResetRenderState
261                }
262                Some(raw_callback) => DrawCmd::RawCallback {
263                    callback: raw_callback,
264                    raw_cmd: cmd,
265                },
266                None => DrawCmd::Elements {
267                    count: cmd.ElemCount as usize,
268                    cmd_params,
269                },
270            }
271        })
272    }
273}
274
275/// Draw command parameters
276#[derive(Copy, Clone, Debug, PartialEq)]
277pub struct DrawCmdParams {
278    /// Clipping rectangle (left, top, right, bottom)
279    pub clip_rect: [f32; 4],
280    /// Texture ID
281    pub texture_id: TextureId,
282    /// Vertex offset
283    pub vtx_offset: usize,
284    /// Index offset
285    pub idx_offset: usize,
286}
287
288/// Draw command
289#[derive(Debug, Clone)]
290pub enum DrawCmd {
291    /// Elements to draw
292    Elements {
293        /// Number of indices
294        count: usize,
295        /// Command parameters
296        cmd_params: DrawCmdParams,
297    },
298    /// Reset render state
299    ResetRenderState,
300    /// Raw callback
301    RawCallback {
302        /// Callback function
303        callback: unsafe extern "C" fn(*const sys::ImDrawList, cmd: *const sys::ImDrawCmd),
304        /// Raw command
305        raw_cmd: *const sys::ImDrawCmd,
306    },
307}
308
309enum DrawListType {
310    Window,
311    Background,
312    Foreground,
313}
314
315/// Object implementing the custom draw API.
316///
317/// Called from [`Ui::get_window_draw_list`], [`Ui::get_background_draw_list`] or [`Ui::get_foreground_draw_list`].
318/// No more than one instance of this structure can live in a program at the same time.
319/// The program will panic on creating a second instance.
320pub struct DrawListMut<'ui> {
321    draw_list_type: DrawListType,
322    draw_list: *mut sys::ImDrawList,
323    _phantom: PhantomData<&'ui ()>,
324}
325
326// Lock for each variant of draw list
327static DRAW_LIST_LOADED_WINDOW: std::sync::atomic::AtomicBool =
328    std::sync::atomic::AtomicBool::new(false);
329static DRAW_LIST_LOADED_BACKGROUND: std::sync::atomic::AtomicBool =
330    std::sync::atomic::AtomicBool::new(false);
331static DRAW_LIST_LOADED_FOREGROUND: std::sync::atomic::AtomicBool =
332    std::sync::atomic::AtomicBool::new(false);
333
334impl Drop for DrawListMut<'_> {
335    fn drop(&mut self) {
336        match self.draw_list_type {
337            DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
338            DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
339            DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
340        }
341        .store(false, std::sync::atomic::Ordering::Release);
342    }
343}
344
345impl DrawListMut<'_> {
346    fn lock_draw_list(t: DrawListType) {
347        let lock = match t {
348            DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
349            DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
350            DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
351        };
352
353        if lock
354            .compare_exchange(
355                false,
356                true,
357                std::sync::atomic::Ordering::Acquire,
358                std::sync::atomic::Ordering::Relaxed,
359            )
360            .is_err()
361        {
362            panic!(
363                "A DrawListMut is already in use! You can only have one DrawListMut in use at a time."
364            );
365        }
366    }
367
368    pub(crate) fn window(_ui: &crate::Ui) -> Self {
369        Self::lock_draw_list(DrawListType::Window);
370        Self {
371            draw_list: unsafe { sys::igGetWindowDrawList() },
372            draw_list_type: DrawListType::Window,
373            _phantom: PhantomData,
374        }
375    }
376
377    pub(crate) fn background(_ui: &crate::Ui) -> Self {
378        Self::lock_draw_list(DrawListType::Background);
379        Self {
380            draw_list: unsafe { sys::igGetBackgroundDrawList(std::ptr::null_mut()) },
381            draw_list_type: DrawListType::Background,
382            _phantom: PhantomData,
383        }
384    }
385
386    pub(crate) fn foreground(_ui: &crate::Ui) -> Self {
387        Self::lock_draw_list(DrawListType::Foreground);
388        Self {
389            draw_list: unsafe { sys::igGetForegroundDrawList_ViewportPtr(std::ptr::null_mut()) },
390            draw_list_type: DrawListType::Foreground,
391            _phantom: PhantomData,
392        }
393    }
394}
395
396/// Drawing functions
397impl<'ui> DrawListMut<'ui> {
398    /// Split draw into multiple channels and merge automatically at the end of the closure.
399    #[doc(alias = "ChannelsSplit")]
400    pub fn channels_split<F: FnOnce(&ChannelsSplit<'ui>)>(&'ui self, channels_count: u32, f: F) {
401        unsafe { sys::ImDrawList_ChannelsSplit(self.draw_list, channels_count as i32) };
402        f(&ChannelsSplit {
403            draw_list: self,
404            channels_count,
405        });
406        unsafe { sys::ImDrawList_ChannelsMerge(self.draw_list) };
407    }
408    /// Returns a line from point `p1` to `p2` with color `c`.
409    pub fn add_line<C>(
410        &'ui self,
411        p1: impl Into<sys::ImVec2>,
412        p2: impl Into<sys::ImVec2>,
413        c: C,
414    ) -> Line<'ui>
415    where
416        C: Into<ImColor32>,
417    {
418        Line::new(self, p1, p2, c)
419    }
420
421    /// Returns a rectangle whose upper-left corner is at point `p1`
422    /// and lower-right corner is at point `p2`, with color `c`.
423    pub fn add_rect<C>(
424        &'ui self,
425        p1: impl Into<sys::ImVec2>,
426        p2: impl Into<sys::ImVec2>,
427        c: C,
428    ) -> Rect<'ui>
429    where
430        C: Into<ImColor32>,
431    {
432        Rect::new(self, p1, p2, c)
433    }
434
435    /// Draw a filled rectangle with per-corner colors (counter-clockwise from upper-left).
436    #[doc(alias = "AddRectFilledMultiColor")]
437    pub fn add_rect_filled_multicolor<C1, C2, C3, C4>(
438        &self,
439        p1: impl Into<sys::ImVec2>,
440        p2: impl Into<sys::ImVec2>,
441        col_upr_left: C1,
442        col_upr_right: C2,
443        col_bot_right: C3,
444        col_bot_left: C4,
445    ) where
446        C1: Into<ImColor32>,
447        C2: Into<ImColor32>,
448        C3: Into<ImColor32>,
449        C4: Into<ImColor32>,
450    {
451        let p_min: sys::ImVec2 = p1.into();
452        let p_max: sys::ImVec2 = p2.into();
453        let c_ul: u32 = col_upr_left.into().into();
454        let c_ur: u32 = col_upr_right.into().into();
455        let c_br: u32 = col_bot_right.into().into();
456        let c_bl: u32 = col_bot_left.into().into();
457        unsafe {
458            sys::ImDrawList_AddRectFilledMultiColor(
459                self.draw_list,
460                p_min,
461                p_max,
462                c_ul,
463                c_ur,
464                c_br,
465                c_bl,
466            );
467        }
468    }
469
470    /// Returns a circle with the given `center`, `radius` and `color`.
471    pub fn add_circle<C>(
472        &'ui self,
473        center: impl Into<sys::ImVec2>,
474        radius: f32,
475        color: C,
476    ) -> Circle<'ui>
477    where
478        C: Into<ImColor32>,
479    {
480        Circle::new(self, center, radius, color)
481    }
482
483    /// Returns a Bezier curve stretching from `pos0` to `pos1`, whose
484    /// curvature is defined by `cp0` and `cp1`.
485    #[doc(alias = "AddBezier", alias = "AddBezierCubic")]
486    pub fn add_bezier_curve(
487        &'ui self,
488        pos0: impl Into<sys::ImVec2>,
489        cp0: impl Into<sys::ImVec2>,
490        cp1: impl Into<sys::ImVec2>,
491        pos1: impl Into<sys::ImVec2>,
492        color: impl Into<ImColor32>,
493    ) -> BezierCurve<'ui> {
494        BezierCurve::new(self, pos0, cp0, cp1, pos1, color)
495    }
496
497    /// Returns a triangle with the given 3 vertices `p1`, `p2` and `p3` and color `c`.
498    #[doc(alias = "AddTriangleFilled", alias = "AddTriangle")]
499    pub fn add_triangle<C>(
500        &'ui self,
501        p1: impl Into<sys::ImVec2>,
502        p2: impl Into<sys::ImVec2>,
503        p3: impl Into<sys::ImVec2>,
504        c: C,
505    ) -> Triangle<'ui>
506    where
507        C: Into<ImColor32>,
508    {
509        Triangle::new(self, p1, p2, p3, c)
510    }
511
512    /// Returns a polygonal line. If filled is rendered as a convex
513    /// polygon, if not filled is drawn as a line specified by
514    /// [`Polyline::thickness`] (default 1.0)
515    #[doc(alias = "AddPolyline", alias = "AddConvexPolyFilled")]
516    pub fn add_polyline<C, P>(&'ui self, points: Vec<P>, c: C) -> Polyline<'ui>
517    where
518        C: Into<ImColor32>,
519        P: Into<sys::ImVec2>,
520    {
521        Polyline::new(self, points, c)
522    }
523
524    // ========== Path Drawing Functions ==========
525
526    /// Clear the current path (i.e. start a new path).
527    #[doc(alias = "PathClear")]
528    pub fn path_clear(&self) {
529        unsafe {
530            // PathClear is inline: _Path.Size = 0;
531            let draw_list = self.draw_list;
532            (*draw_list)._Path.Size = 0;
533        }
534    }
535
536    /// Add a point to the current path.
537    #[doc(alias = "PathLineTo")]
538    pub fn path_line_to(&self, pos: impl Into<sys::ImVec2>) {
539        unsafe { sys::ImDrawList_PathLineTo(self.draw_list, pos.into()) }
540    }
541
542    /// Add a point to the current path, merging duplicate points.
543    #[doc(alias = "PathLineToMergeDuplicate")]
544    pub fn path_line_to_merge_duplicate(&self, pos: impl Into<sys::ImVec2>) {
545        unsafe { sys::ImDrawList_PathLineToMergeDuplicate(self.draw_list, pos.into()) }
546    }
547
548    /// Add an arc to the current path.
549    #[doc(alias = "PathArcTo")]
550    pub fn path_arc_to(
551        &self,
552        center: impl Into<sys::ImVec2>,
553        radius: f32,
554        a_min: f32,
555        a_max: f32,
556        num_segments: i32,
557    ) {
558        unsafe {
559            let center_vec: sys::ImVec2 = center.into();
560            sys::ImDrawList_PathArcTo(
561                self.draw_list,
562                center_vec,
563                radius,
564                a_min,
565                a_max,
566                num_segments,
567            );
568        }
569    }
570
571    /// Add an arc to the current path using fast precomputed angles.
572    #[doc(alias = "PathArcToFast")]
573    pub fn path_arc_to_fast(
574        &self,
575        center: impl Into<sys::ImVec2>,
576        radius: f32,
577        a_min_of_12: i32,
578        a_max_of_12: i32,
579    ) {
580        unsafe {
581            let center_vec: sys::ImVec2 = center.into();
582            sys::ImDrawList_PathArcToFast(
583                self.draw_list,
584                center_vec,
585                radius,
586                a_min_of_12,
587                a_max_of_12,
588            );
589        }
590    }
591
592    /// Add a rectangle to the current path.
593    #[doc(alias = "PathRect")]
594    pub fn path_rect(
595        &self,
596        rect_min: impl Into<sys::ImVec2>,
597        rect_max: impl Into<sys::ImVec2>,
598        rounding: f32,
599        flags: DrawFlags,
600    ) {
601        unsafe {
602            let min_vec: sys::ImVec2 = rect_min.into();
603            let max_vec: sys::ImVec2 = rect_max.into();
604            sys::ImDrawList_PathRect(
605                self.draw_list,
606                min_vec,
607                max_vec,
608                rounding,
609                flags.bits() as sys::ImDrawFlags,
610            );
611        }
612    }
613
614    /// Add an elliptical arc to the current path.
615    #[doc(alias = "PathEllipticalArcTo")]
616    pub fn path_elliptical_arc_to(
617        &self,
618        center: impl Into<sys::ImVec2>,
619        radius: impl Into<sys::ImVec2>,
620        rot: f32,
621        a_min: f32,
622        a_max: f32,
623        num_segments: i32,
624    ) {
625        unsafe {
626            sys::ImDrawList_PathEllipticalArcTo(
627                self.draw_list,
628                center.into(),
629                radius.into(),
630                rot,
631                a_min,
632                a_max,
633                num_segments,
634            )
635        }
636    }
637
638    /// Add a quadratic bezier curve to the current path.
639    #[doc(alias = "PathBezierQuadraticCurveTo")]
640    pub fn path_bezier_quadratic_curve_to(
641        &self,
642        p2: impl Into<sys::ImVec2>,
643        p3: impl Into<sys::ImVec2>,
644        num_segments: i32,
645    ) {
646        unsafe {
647            sys::ImDrawList_PathBezierQuadraticCurveTo(
648                self.draw_list,
649                p2.into(),
650                p3.into(),
651                num_segments,
652            )
653        }
654    }
655
656    /// Add a cubic bezier curve to the current path.
657    #[doc(alias = "PathBezierCubicCurveTo")]
658    pub fn path_bezier_cubic_curve_to(
659        &self,
660        p2: impl Into<sys::ImVec2>,
661        p3: impl Into<sys::ImVec2>,
662        p4: impl Into<sys::ImVec2>,
663        num_segments: i32,
664    ) {
665        unsafe {
666            sys::ImDrawList_PathBezierCubicCurveTo(
667                self.draw_list,
668                p2.into(),
669                p3.into(),
670                p4.into(),
671                num_segments,
672            )
673        }
674    }
675
676    /// Stroke the current path with the specified color and thickness.
677    #[doc(alias = "PathStroke")]
678    pub fn path_stroke(&self, color: impl Into<ImColor32>, flags: DrawFlags, thickness: f32) {
679        unsafe {
680            // PathStroke is inline: AddPolyline(_Path.Data, _Path.Size, col, flags, thickness); _Path.Size = 0;
681            let draw_list = self.draw_list;
682            let path = &mut (*draw_list)._Path;
683
684            if path.Size > 0 {
685                sys::ImDrawList_AddPolyline(
686                    self.draw_list,
687                    path.Data,
688                    path.Size,
689                    color.into().into(),
690                    flags.bits() as sys::ImDrawFlags,
691                    thickness,
692                );
693                path.Size = 0; // Clear path after stroking
694            }
695        }
696    }
697
698    /// Fill the current path as a convex polygon.
699    #[doc(alias = "PathFillConvex")]
700    pub fn path_fill_convex(&self, color: impl Into<ImColor32>) {
701        unsafe {
702            // PathFillConvex is inline: AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0;
703            let draw_list = self.draw_list;
704            let path = &mut (*draw_list)._Path;
705
706            if path.Size > 0 {
707                sys::ImDrawList_AddConvexPolyFilled(
708                    self.draw_list,
709                    path.Data,
710                    path.Size,
711                    color.into().into(),
712                );
713                path.Size = 0; // Clear path after filling
714            }
715        }
716    }
717
718    /// Draw a text whose upper-left corner is at point `pos`.
719    pub fn add_text(
720        &self,
721        pos: impl Into<sys::ImVec2>,
722        col: impl Into<ImColor32>,
723        text: impl AsRef<str>,
724    ) {
725        use std::os::raw::c_char;
726
727        let text = text.as_ref();
728        let pos: sys::ImVec2 = pos.into();
729        let col = col.into();
730
731        unsafe {
732            let start = text.as_ptr() as *const c_char;
733            let end = (start as usize + text.len()) as *const c_char;
734            sys::ImDrawList_AddText_Vec2(self.draw_list, pos, col.into(), start, end);
735        }
736    }
737
738    /// Draw text with an explicit font and optional fine CPU clip rectangle.
739    ///
740    /// This mirrors Dear ImGui's `ImDrawList::AddText(ImFont*, ...)` overload.
741    #[doc(alias = "AddText")]
742    pub fn add_text_with_font(
743        &self,
744        font: &crate::fonts::Font,
745        font_size: f32,
746        pos: impl Into<sys::ImVec2>,
747        col: impl Into<ImColor32>,
748        text: impl AsRef<str>,
749        wrap_width: f32,
750        cpu_fine_clip_rect: Option<[f32; 4]>,
751    ) {
752        use std::os::raw::c_char;
753        let text = text.as_ref();
754        let pos: sys::ImVec2 = pos.into();
755        let col = col.into();
756        let font_ptr = font.raw();
757
758        let clip_vec4 = cpu_fine_clip_rect.map(|r| sys::ImVec4 {
759            x: r[0],
760            y: r[1],
761            z: r[2],
762            w: r[3],
763        });
764        let clip_ptr = match clip_vec4.as_ref() {
765            Some(v) => v as *const sys::ImVec4,
766            None => std::ptr::null(),
767        };
768
769        unsafe {
770            let start = text.as_ptr() as *const c_char;
771            let end = (start as usize + text.len()) as *const c_char;
772            sys::ImDrawList_AddText_FontPtr(
773                self.draw_list,
774                font_ptr,
775                font_size,
776                pos,
777                col.into(),
778                start,
779                end,
780                wrap_width,
781                clip_ptr,
782            );
783        }
784    }
785
786    // channels_split is provided on DrawListMut
787
788    /// Push a texture on the drawlist texture stack (ImGui 1.92+)
789    ///
790    /// While pushed, image and primitives will use this texture unless otherwise specified.
791    ///
792    /// Example:
793    /// ```no_run
794    /// # use dear_imgui::*;
795    /// # fn demo(ui: &Ui) {
796    /// let dl = ui.get_window_draw_list();
797    /// let tex = texture::TextureId::new(1);
798    /// dl.push_texture(tex);
799    /// dl.add_image(tex, [10.0,10.0], [110.0,110.0], [0.0,0.0], [1.0,1.0], Color::WHITE);
800    /// dl.pop_texture();
801    /// # }
802    /// ```
803    #[doc(alias = "PushTexture")]
804    pub fn push_texture(&self, texture: impl Into<crate::texture::TextureRef>) {
805        let tex_ref = texture.into().raw();
806        unsafe { sys::ImDrawList_PushTexture(self.draw_list, tex_ref) }
807    }
808
809    /// Pop the last texture from the drawlist texture stack (ImGui 1.92+)
810    #[doc(alias = "PopTexture")]
811    pub fn pop_texture(&self) {
812        unsafe {
813            sys::ImDrawList_PopTexture(self.draw_list);
814        }
815    }
816
817    /// Push a clip rectangle, optionally intersecting with the current clip rect.
818    #[doc(alias = "PushClipRect")]
819    pub fn push_clip_rect(
820        &self,
821        clip_rect_min: impl Into<sys::ImVec2>,
822        clip_rect_max: impl Into<sys::ImVec2>,
823        intersect_with_current: bool,
824    ) {
825        unsafe {
826            sys::ImDrawList_PushClipRect(
827                self.draw_list,
828                clip_rect_min.into(),
829                clip_rect_max.into(),
830                intersect_with_current,
831            )
832        }
833    }
834
835    /// Push a full-screen clip rectangle.
836    #[doc(alias = "PushClipRectFullScreen")]
837    pub fn push_clip_rect_full_screen(&self) {
838        unsafe { sys::ImDrawList_PushClipRectFullScreen(self.draw_list) }
839    }
840
841    /// Pop the last clip rectangle.
842    #[doc(alias = "PopClipRect")]
843    pub fn pop_clip_rect(&self) {
844        unsafe { sys::ImDrawList_PopClipRect(self.draw_list) }
845    }
846
847    /// Get current minimum clip rectangle point.
848    pub fn clip_rect_min(&self) -> [f32; 2] {
849        let mut out = sys::ImVec2 { x: 0.0, y: 0.0 };
850        unsafe { sys::ImDrawList_GetClipRectMin(&mut out as *mut sys::ImVec2, self.draw_list) };
851        out.into()
852    }
853
854    /// Get current maximum clip rectangle point.
855    pub fn clip_rect_max(&self) -> [f32; 2] {
856        let mut out = sys::ImVec2 { x: 0.0, y: 0.0 };
857        unsafe { sys::ImDrawList_GetClipRectMax(&mut out as *mut sys::ImVec2, self.draw_list) };
858        out.into()
859    }
860
861    /// Convenience: push a clip rect, run f, pop.
862    pub fn with_clip_rect<F>(
863        &self,
864        clip_rect_min: impl Into<sys::ImVec2>,
865        clip_rect_max: impl Into<sys::ImVec2>,
866        f: F,
867    ) where
868        F: FnOnce(),
869    {
870        self.push_clip_rect(clip_rect_min, clip_rect_max, false);
871        f();
872        self.pop_clip_rect();
873    }
874
875    /// Add an image quad (axis-aligned). Tint via `col`.
876    #[doc(alias = "AddImage")]
877    pub fn add_image(
878        &self,
879        texture: impl Into<crate::texture::TextureRef>,
880        p_min: impl Into<sys::ImVec2>,
881        p_max: impl Into<sys::ImVec2>,
882        uv_min: impl Into<sys::ImVec2>,
883        uv_max: impl Into<sys::ImVec2>,
884        col: impl Into<ImColor32>,
885    ) {
886        // Example:
887        // let tex = texture::TextureId::new(5);
888        // self.add_image(tex, [10.0,10.0], [110.0,110.0], [0.0,0.0], [1.0,1.0], Color::WHITE);
889        let p_min: sys::ImVec2 = p_min.into();
890        let p_max: sys::ImVec2 = p_max.into();
891        let uv_min: sys::ImVec2 = uv_min.into();
892        let uv_max: sys::ImVec2 = uv_max.into();
893        let col = col.into().to_bits();
894        let tex_ref = texture.into().raw();
895        unsafe {
896            sys::ImDrawList_AddImage(self.draw_list, tex_ref, p_min, p_max, uv_min, uv_max, col)
897        }
898    }
899
900    /// Add an image with 4 arbitrary corners.
901    #[doc(alias = "AddImageQuad")]
902    pub fn add_image_quad(
903        &self,
904        texture: impl Into<crate::texture::TextureRef>,
905        p1: impl Into<sys::ImVec2>,
906        p2: impl Into<sys::ImVec2>,
907        p3: impl Into<sys::ImVec2>,
908        p4: impl Into<sys::ImVec2>,
909        uv1: impl Into<sys::ImVec2>,
910        uv2: impl Into<sys::ImVec2>,
911        uv3: impl Into<sys::ImVec2>,
912        uv4: impl Into<sys::ImVec2>,
913        col: impl Into<ImColor32>,
914    ) {
915        // Example:
916        // let tex = texture::TextureId::new(5);
917        // self.add_image_quad(
918        //     tex,
919        //     [10.0,10.0], [110.0,20.0], [120.0,120.0], [5.0,100.0],
920        //     [0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0],
921        //     Color::WHITE,
922        // );
923        let p1: sys::ImVec2 = p1.into();
924        let p2: sys::ImVec2 = p2.into();
925        let p3: sys::ImVec2 = p3.into();
926        let p4: sys::ImVec2 = p4.into();
927        let uv1: sys::ImVec2 = uv1.into();
928        let uv2: sys::ImVec2 = uv2.into();
929        let uv3: sys::ImVec2 = uv3.into();
930        let uv4: sys::ImVec2 = uv4.into();
931        let col = col.into().to_bits();
932        let tex_ref = texture.into().raw();
933        unsafe {
934            sys::ImDrawList_AddImageQuad(
935                self.draw_list,
936                tex_ref,
937                p1,
938                p2,
939                p3,
940                p4,
941                uv1,
942                uv2,
943                uv3,
944                uv4,
945                col,
946            )
947        }
948    }
949
950    /// Add an axis-aligned rounded image.
951    #[doc(alias = "AddImageRounded")]
952    pub fn add_image_rounded(
953        &self,
954        texture: impl Into<crate::texture::TextureRef>,
955        p_min: impl Into<sys::ImVec2>,
956        p_max: impl Into<sys::ImVec2>,
957        uv_min: impl Into<sys::ImVec2>,
958        uv_max: impl Into<sys::ImVec2>,
959        col: impl Into<ImColor32>,
960        rounding: f32,
961        flags: DrawFlags,
962    ) {
963        // Example:
964        // let tex = texture::TextureId::new(5);
965        // self.add_image_rounded(
966        //     tex,
967        //     [10.0,10.0], [110.0,110.0],
968        //     [0.0,0.0], [1.0,1.0],
969        //     Color::WHITE,
970        //     8.0,
971        //     DrawFlags::ROUND_CORNERS_ALL,
972        // );
973        let p_min: sys::ImVec2 = p_min.into();
974        let p_max: sys::ImVec2 = p_max.into();
975        let uv_min: sys::ImVec2 = uv_min.into();
976        let uv_max: sys::ImVec2 = uv_max.into();
977        let col = col.into().to_bits();
978        let tex_ref = texture.into().raw();
979        unsafe {
980            sys::ImDrawList_AddImageRounded(
981                self.draw_list,
982                tex_ref,
983                p_min,
984                p_max,
985                uv_min,
986                uv_max,
987                col,
988                rounding,
989                flags.bits() as sys::ImDrawFlags,
990            )
991        }
992    }
993
994    /// Draw a quadrilateral outline given four points.
995    #[doc(alias = "AddQuad")]
996    pub fn add_quad<C>(
997        &self,
998        p1: impl Into<sys::ImVec2>,
999        p2: impl Into<sys::ImVec2>,
1000        p3: impl Into<sys::ImVec2>,
1001        p4: impl Into<sys::ImVec2>,
1002        col: C,
1003        thickness: f32,
1004    ) where
1005        C: Into<ImColor32>,
1006    {
1007        unsafe {
1008            sys::ImDrawList_AddQuad(
1009                self.draw_list,
1010                p1.into(),
1011                p2.into(),
1012                p3.into(),
1013                p4.into(),
1014                col.into().into(),
1015                thickness,
1016            )
1017        }
1018    }
1019
1020    /// Draw a filled quadrilateral given four points.
1021    #[doc(alias = "AddQuadFilled")]
1022    pub fn add_quad_filled<C>(
1023        &self,
1024        p1: impl Into<sys::ImVec2>,
1025        p2: impl Into<sys::ImVec2>,
1026        p3: impl Into<sys::ImVec2>,
1027        p4: impl Into<sys::ImVec2>,
1028        col: C,
1029    ) where
1030        C: Into<ImColor32>,
1031    {
1032        unsafe {
1033            sys::ImDrawList_AddQuadFilled(
1034                self.draw_list,
1035                p1.into(),
1036                p2.into(),
1037                p3.into(),
1038                p4.into(),
1039                col.into().into(),
1040            )
1041        }
1042    }
1043
1044    /// Draw a regular n-gon outline.
1045    #[doc(alias = "AddNgon")]
1046    pub fn add_ngon<C>(
1047        &self,
1048        center: impl Into<sys::ImVec2>,
1049        radius: f32,
1050        col: C,
1051        num_segments: i32,
1052        thickness: f32,
1053    ) where
1054        C: Into<ImColor32>,
1055    {
1056        unsafe {
1057            sys::ImDrawList_AddNgon(
1058                self.draw_list,
1059                center.into(),
1060                radius,
1061                col.into().into(),
1062                num_segments,
1063                thickness,
1064            )
1065        }
1066    }
1067
1068    /// Draw a filled regular n-gon.
1069    #[doc(alias = "AddNgonFilled")]
1070    pub fn add_ngon_filled<C>(
1071        &self,
1072        center: impl Into<sys::ImVec2>,
1073        radius: f32,
1074        col: C,
1075        num_segments: i32,
1076    ) where
1077        C: Into<ImColor32>,
1078    {
1079        unsafe {
1080            sys::ImDrawList_AddNgonFilled(
1081                self.draw_list,
1082                center.into(),
1083                radius,
1084                col.into().into(),
1085                num_segments,
1086            )
1087        }
1088    }
1089
1090    /// Draw an ellipse outline.
1091    #[doc(alias = "AddEllipse")]
1092    pub fn add_ellipse<C>(
1093        &self,
1094        center: impl Into<sys::ImVec2>,
1095        radius: impl Into<sys::ImVec2>,
1096        col: C,
1097        rot: f32,
1098        num_segments: i32,
1099        thickness: f32,
1100    ) where
1101        C: Into<ImColor32>,
1102    {
1103        unsafe {
1104            sys::ImDrawList_AddEllipse(
1105                self.draw_list,
1106                center.into(),
1107                radius.into(),
1108                col.into().into(),
1109                rot,
1110                num_segments,
1111                thickness,
1112            )
1113        }
1114    }
1115
1116    /// Draw a filled ellipse.
1117    #[doc(alias = "AddEllipseFilled")]
1118    pub fn add_ellipse_filled<C>(
1119        &self,
1120        center: impl Into<sys::ImVec2>,
1121        radius: impl Into<sys::ImVec2>,
1122        col: C,
1123        rot: f32,
1124        num_segments: i32,
1125    ) where
1126        C: Into<ImColor32>,
1127    {
1128        unsafe {
1129            sys::ImDrawList_AddEllipseFilled(
1130                self.draw_list,
1131                center.into(),
1132                radius.into(),
1133                col.into().into(),
1134                rot,
1135                num_segments,
1136            )
1137        }
1138    }
1139
1140    /// Draw a quadratic Bezier curve directly.
1141    #[doc(alias = "AddBezierQuadratic")]
1142    pub fn add_bezier_quadratic<C>(
1143        &self,
1144        p1: impl Into<sys::ImVec2>,
1145        p2: impl Into<sys::ImVec2>,
1146        p3: impl Into<sys::ImVec2>,
1147        col: C,
1148        thickness: f32,
1149        num_segments: i32,
1150    ) where
1151        C: Into<ImColor32>,
1152    {
1153        unsafe {
1154            sys::ImDrawList_AddBezierQuadratic(
1155                self.draw_list,
1156                p1.into(),
1157                p2.into(),
1158                p3.into(),
1159                col.into().into(),
1160                thickness,
1161                num_segments,
1162            )
1163        }
1164    }
1165
1166    /// Fill a concave polygon (Dear ImGui 1.92+).
1167    #[doc(alias = "AddConcavePolyFilled")]
1168    pub fn add_concave_poly_filled<C, P>(&self, points: &[P], col: C)
1169    where
1170        C: Into<ImColor32>,
1171        P: Copy + Into<sys::ImVec2>,
1172    {
1173        let mut buf: Vec<sys::ImVec2> = Vec::with_capacity(points.len());
1174        for p in points.iter().copied() {
1175            buf.push(p.into());
1176        }
1177        unsafe {
1178            sys::ImDrawList_AddConcavePolyFilled(
1179                self.draw_list,
1180                buf.as_ptr(),
1181                buf.len() as i32,
1182                col.into().into(),
1183            )
1184        }
1185    }
1186
1187    /// Fill the current path as a concave polygon (Dear ImGui 1.92+).
1188    #[doc(alias = "PathFillConcave")]
1189    pub fn path_fill_concave(&self, color: impl Into<ImColor32>) {
1190        unsafe { sys::ImDrawList_PathFillConcave(self.draw_list, color.into().into()) }
1191    }
1192
1193    /// Insert a raw draw callback.
1194    ///
1195    /// Safety: The callback must be an `extern "C"` function compatible with `ImDrawCallback`.
1196    /// The provided `userdata` must remain valid until the draw list is executed by the renderer.
1197    /// If you allocate memory and store its pointer in `userdata`, you are responsible for reclaiming it
1198    /// from within the callback or otherwise ensuring no leaks occur. Note that callbacks are only invoked
1199    /// if the draw list is actually rendered.
1200    #[doc(alias = "AddCallback")]
1201    pub unsafe fn add_callback(
1202        &self,
1203        callback: sys::ImDrawCallback,
1204        userdata: *mut std::os::raw::c_void,
1205        userdata_size: usize,
1206    ) {
1207        unsafe { sys::ImDrawList_AddCallback(self.draw_list, callback, userdata, userdata_size) }
1208    }
1209
1210    /// Insert a new draw command (forces a new draw call boundary).
1211    #[doc(alias = "AddDrawCmd")]
1212    pub fn add_draw_cmd(&self) {
1213        unsafe { sys::ImDrawList_AddDrawCmd(self.draw_list) }
1214    }
1215
1216    /// Clone the current draw list output into an owned, independent copy.
1217    ///
1218    /// The returned draw list is heap-allocated by Dear ImGui and will be destroyed on drop.
1219    #[doc(alias = "CloneOutput")]
1220    pub fn clone_output(&self) -> OwnedDrawList {
1221        unsafe { OwnedDrawList::from_raw(sys::ImDrawList_CloneOutput(self.draw_list)) }
1222    }
1223}
1224
1225/// Represent the drawing interface within a call to `channels_split`.
1226pub struct ChannelsSplit<'ui> {
1227    draw_list: &'ui DrawListMut<'ui>,
1228    channels_count: u32,
1229}
1230
1231impl ChannelsSplit<'_> {
1232    /// Change current channel. Panics if `channel_index >= channels_count`.
1233    #[doc(alias = "ChannelsSetCurrent")]
1234    pub fn set_current(&self, channel_index: u32) {
1235        assert!(
1236            channel_index < self.channels_count,
1237            "Channel index {} out of range {}",
1238            channel_index,
1239            self.channels_count
1240        );
1241        unsafe {
1242            sys::ImDrawList_ChannelsSetCurrent(self.draw_list.draw_list, channel_index as i32)
1243        };
1244    }
1245}
1246
1247/// A safe builder for registering a Rust callback to be executed during draw.
1248#[must_use = "call .build() to register the callback"]
1249pub struct Callback<'ui, F> {
1250    draw_list: &'ui DrawListMut<'ui>,
1251    callback: F,
1252}
1253
1254impl<'ui, F: FnOnce() + 'static> Callback<'ui, F> {
1255    /// Construct a new callback builder. Typically created via `DrawListMut::add_callback_safe`.
1256    pub fn new(draw_list: &'ui DrawListMut<'_>, callback: F) -> Self {
1257        Self {
1258            draw_list,
1259            callback,
1260        }
1261    }
1262
1263    /// Register the callback with the draw list.
1264    pub fn build(self) {
1265        use std::os::raw::c_void;
1266        // Box the closure so we can pass an owning pointer to C.
1267        let ptr: *mut F = Box::into_raw(Box::new(self.callback));
1268        unsafe {
1269            sys::ImDrawList_AddCallback(
1270                self.draw_list.draw_list,
1271                Some(Self::run_callback),
1272                ptr as *mut c_void,
1273                std::mem::size_of::<F>(),
1274            );
1275        }
1276    }
1277
1278    unsafe extern "C" fn run_callback(
1279        _parent_list: *const sys::ImDrawList,
1280        cmd: *const sys::ImDrawCmd,
1281    ) {
1282        // Access mutable ImDrawCmd to retrieve and clear user data
1283        let cmd = &mut *(cmd as *mut sys::ImDrawCmd);
1284        // Compute pointer to our boxed closure (respect offset if ever used)
1285        let data_ptr =
1286            (cmd.UserCallbackData as *mut u8).add(cmd.UserCallbackDataOffset as usize) as *mut F;
1287        if data_ptr.is_null() {
1288            return;
1289        }
1290        // Take ownership and clear the pointer/size to avoid double-free or re-entry
1291        cmd.UserCallbackData = std::ptr::null_mut();
1292        cmd.UserCallbackDataSize = 0;
1293        cmd.UserCallbackDataOffset = 0;
1294        let cb = Box::from_raw(data_ptr);
1295        cb();
1296    }
1297}
1298
1299impl<'ui> DrawListMut<'ui> {
1300    /// Safe variant: add a Rust callback (executed when the draw list is rendered).
1301    /// Note: if the draw list is never rendered, the callback will not run and its resources won't be reclaimed.
1302    pub fn add_callback_safe<F: FnOnce() + 'static>(&'ui self, callback: F) -> Callback<'ui, F> {
1303        Callback::new(self, callback)
1304    }
1305}
1306
1307impl<'ui> DrawListMut<'ui> {
1308    /// Unsafe low-level geometry API: reserve index and vertex space.
1309    ///
1310    /// Safety: Caller must write exactly the reserved amount using PrimWrite* and ensure valid topology.
1311    pub unsafe fn prim_reserve(&self, idx_count: i32, vtx_count: i32) {
1312        sys::ImDrawList_PrimReserve(self.draw_list, idx_count, vtx_count)
1313    }
1314
1315    /// Unsafe low-level geometry API: unreserve previously reserved space.
1316    ///
1317    /// Safety: Must match a prior call to `prim_reserve` which hasn't been fully written.
1318    pub unsafe fn prim_unreserve(&self, idx_count: i32, vtx_count: i32) {
1319        sys::ImDrawList_PrimUnreserve(self.draw_list, idx_count, vtx_count)
1320    }
1321
1322    /// Unsafe low-level geometry API: append a rectangle primitive with a single color.
1323    ///
1324    /// Safety: Only use between `prim_reserve` and completing the reserved writes.
1325    pub unsafe fn prim_rect(
1326        &self,
1327        a: impl Into<sys::ImVec2>,
1328        b: impl Into<sys::ImVec2>,
1329        col: impl Into<ImColor32>,
1330    ) {
1331        sys::ImDrawList_PrimRect(self.draw_list, a.into(), b.into(), col.into().into())
1332    }
1333
1334    /// Unsafe low-level geometry API: append a rectangle primitive with UVs and color.
1335    ///
1336    /// Safety: Only use between `prim_reserve` and completing the reserved writes.
1337    pub unsafe fn prim_rect_uv(
1338        &self,
1339        a: impl Into<sys::ImVec2>,
1340        b: impl Into<sys::ImVec2>,
1341        uv_a: impl Into<sys::ImVec2>,
1342        uv_b: impl Into<sys::ImVec2>,
1343        col: impl Into<ImColor32>,
1344    ) {
1345        sys::ImDrawList_PrimRectUV(
1346            self.draw_list,
1347            a.into(),
1348            b.into(),
1349            uv_a.into(),
1350            uv_b.into(),
1351            col.into().into(),
1352        )
1353    }
1354
1355    /// Unsafe low-level geometry API: append a quad primitive with UVs and color.
1356    ///
1357    /// Safety: Only use between `prim_reserve` and completing the reserved writes.
1358    pub unsafe fn prim_quad_uv(
1359        &self,
1360        a: impl Into<sys::ImVec2>,
1361        b: impl Into<sys::ImVec2>,
1362        c: impl Into<sys::ImVec2>,
1363        d: impl Into<sys::ImVec2>,
1364        uv_a: impl Into<sys::ImVec2>,
1365        uv_b: impl Into<sys::ImVec2>,
1366        uv_c: impl Into<sys::ImVec2>,
1367        uv_d: impl Into<sys::ImVec2>,
1368        col: impl Into<ImColor32>,
1369    ) {
1370        sys::ImDrawList_PrimQuadUV(
1371            self.draw_list,
1372            a.into(),
1373            b.into(),
1374            c.into(),
1375            d.into(),
1376            uv_a.into(),
1377            uv_b.into(),
1378            uv_c.into(),
1379            uv_d.into(),
1380            col.into().into(),
1381        )
1382    }
1383
1384    /// Unsafe low-level geometry API: write a vertex.
1385    ///
1386    /// Safety: Only use to fill space reserved by `prim_reserve`.
1387    pub unsafe fn prim_write_vtx(
1388        &self,
1389        pos: impl Into<sys::ImVec2>,
1390        uv: impl Into<sys::ImVec2>,
1391        col: impl Into<ImColor32>,
1392    ) {
1393        sys::ImDrawList_PrimWriteVtx(self.draw_list, pos.into(), uv.into(), col.into().into())
1394    }
1395
1396    /// Unsafe low-level geometry API: write an index.
1397    ///
1398    /// Safety: Only use to fill space reserved by `prim_reserve`.
1399    pub unsafe fn prim_write_idx(&self, idx: sys::ImDrawIdx) {
1400        sys::ImDrawList_PrimWriteIdx(self.draw_list, idx)
1401    }
1402
1403    /// Unsafe low-level geometry API: convenience to append one vertex (pos+uv+col).
1404    ///
1405    /// Safety: Only use between `prim_reserve` and completing the reserved writes.
1406    pub unsafe fn prim_vtx(
1407        &self,
1408        pos: impl Into<sys::ImVec2>,
1409        uv: impl Into<sys::ImVec2>,
1410        col: impl Into<ImColor32>,
1411    ) {
1412        sys::ImDrawList_PrimVtx(self.draw_list, pos.into(), uv.into(), col.into().into())
1413    }
1414}
1415
1416/// Represents a line about to be drawn
1417#[must_use = "should call .build() to draw the object"]
1418pub struct Line<'ui> {
1419    p1: [f32; 2],
1420    p2: [f32; 2],
1421    color: ImColor32,
1422    thickness: f32,
1423    draw_list: &'ui DrawListMut<'ui>,
1424}
1425
1426impl<'ui> Line<'ui> {
1427    fn new<C>(
1428        draw_list: &'ui DrawListMut<'_>,
1429        p1: impl Into<sys::ImVec2>,
1430        p2: impl Into<sys::ImVec2>,
1431        c: C,
1432    ) -> Self
1433    where
1434        C: Into<ImColor32>,
1435    {
1436        Self {
1437            p1: {
1438                let v: sys::ImVec2 = p1.into();
1439                v.into()
1440            },
1441            p2: {
1442                let v: sys::ImVec2 = p2.into();
1443                v.into()
1444            },
1445            color: c.into(),
1446            thickness: 1.0,
1447            draw_list,
1448        }
1449    }
1450
1451    /// Set line's thickness (default to 1.0 pixel)
1452    pub fn thickness(mut self, thickness: f32) -> Self {
1453        self.thickness = thickness;
1454        self
1455    }
1456
1457    /// Draw the line on the window
1458    pub fn build(self) {
1459        unsafe {
1460            let p1 = sys::ImVec2 {
1461                x: self.p1[0],
1462                y: self.p1[1],
1463            };
1464            let p2 = sys::ImVec2 {
1465                x: self.p2[0],
1466                y: self.p2[1],
1467            };
1468            sys::ImDrawList_AddLine(
1469                self.draw_list.draw_list,
1470                p1,
1471                p2,
1472                self.color.into(),
1473                self.thickness,
1474            )
1475        }
1476    }
1477}
1478
1479/// Represents a rectangle about to be drawn
1480#[must_use = "should call .build() to draw the object"]
1481pub struct Rect<'ui> {
1482    p1: [f32; 2],
1483    p2: [f32; 2],
1484    color: ImColor32,
1485    rounding: f32,
1486    flags: DrawFlags,
1487    thickness: f32,
1488    filled: bool,
1489    draw_list: &'ui DrawListMut<'ui>,
1490}
1491
1492impl<'ui> Rect<'ui> {
1493    fn new<C>(
1494        draw_list: &'ui DrawListMut<'_>,
1495        p1: impl Into<sys::ImVec2>,
1496        p2: impl Into<sys::ImVec2>,
1497        c: C,
1498    ) -> Self
1499    where
1500        C: Into<ImColor32>,
1501    {
1502        Self {
1503            p1: {
1504                let v: sys::ImVec2 = p1.into();
1505                v.into()
1506            },
1507            p2: {
1508                let v: sys::ImVec2 = p2.into();
1509                v.into()
1510            },
1511            color: c.into(),
1512            rounding: 0.0,
1513            flags: DrawFlags::ROUND_CORNERS_ALL,
1514            thickness: 1.0,
1515            filled: false,
1516            draw_list,
1517        }
1518    }
1519
1520    /// Set rectangle's corner rounding (default to 0.0 = no rounding)
1521    pub fn rounding(mut self, rounding: f32) -> Self {
1522        self.rounding = rounding;
1523        self
1524    }
1525
1526    /// Set rectangle's thickness (default to 1.0 pixel). Has no effect if filled
1527    pub fn thickness(mut self, thickness: f32) -> Self {
1528        self.thickness = thickness;
1529        self
1530    }
1531
1532    /// Draw rectangle as filled
1533    pub fn filled(mut self, filled: bool) -> Self {
1534        self.filled = filled;
1535        self
1536    }
1537
1538    /// Set rectangle's corner flags
1539    pub fn flags(mut self, flags: DrawFlags) -> Self {
1540        self.flags = flags;
1541        self
1542    }
1543
1544    /// Draw the rectangle on the window
1545    pub fn build(self) {
1546        let p1 = sys::ImVec2 {
1547            x: self.p1[0],
1548            y: self.p1[1],
1549        };
1550        let p2 = sys::ImVec2 {
1551            x: self.p2[0],
1552            y: self.p2[1],
1553        };
1554
1555        if self.filled {
1556            unsafe {
1557                sys::ImDrawList_AddRectFilled(
1558                    self.draw_list.draw_list,
1559                    p1,
1560                    p2,
1561                    self.color.into(),
1562                    self.rounding,
1563                    self.flags.bits() as sys::ImDrawFlags,
1564                )
1565            }
1566        } else {
1567            unsafe {
1568                sys::ImDrawList_AddRect(
1569                    self.draw_list.draw_list,
1570                    p1,
1571                    p2,
1572                    self.color.into(),
1573                    self.rounding,
1574                    self.flags.bits() as sys::ImDrawFlags,
1575                    self.thickness,
1576                )
1577            }
1578        }
1579    }
1580}
1581
1582/// Represents a circle about to be drawn
1583#[must_use = "should call .build() to draw the object"]
1584pub struct Circle<'ui> {
1585    center: [f32; 2],
1586    radius: f32,
1587    color: ImColor32,
1588    num_segments: i32,
1589    thickness: f32,
1590    filled: bool,
1591    draw_list: &'ui DrawListMut<'ui>,
1592}
1593
1594impl<'ui> Circle<'ui> {
1595    fn new<C>(
1596        draw_list: &'ui DrawListMut<'_>,
1597        center: impl Into<sys::ImVec2>,
1598        radius: f32,
1599        color: C,
1600    ) -> Self
1601    where
1602        C: Into<ImColor32>,
1603    {
1604        Self {
1605            center: {
1606                let v: sys::ImVec2 = center.into();
1607                v.into()
1608            },
1609            radius,
1610            color: color.into(),
1611            num_segments: 0, // 0 = auto
1612            thickness: 1.0,
1613            filled: false,
1614            draw_list,
1615        }
1616    }
1617
1618    /// Set circle's thickness (default to 1.0 pixel). Has no effect if filled
1619    pub fn thickness(mut self, thickness: f32) -> Self {
1620        self.thickness = thickness;
1621        self
1622    }
1623
1624    /// Draw circle as filled
1625    pub fn filled(mut self, filled: bool) -> Self {
1626        self.filled = filled;
1627        self
1628    }
1629
1630    /// Set number of segments (default to 0 = auto)
1631    pub fn num_segments(mut self, num_segments: i32) -> Self {
1632        self.num_segments = num_segments;
1633        self
1634    }
1635
1636    /// Draw the circle on the window
1637    pub fn build(self) {
1638        let center = sys::ImVec2 {
1639            x: self.center[0],
1640            y: self.center[1],
1641        };
1642
1643        if self.filled {
1644            unsafe {
1645                sys::ImDrawList_AddCircleFilled(
1646                    self.draw_list.draw_list,
1647                    center,
1648                    self.radius,
1649                    self.color.into(),
1650                    self.num_segments,
1651                )
1652            }
1653        } else {
1654            unsafe {
1655                sys::ImDrawList_AddCircle(
1656                    self.draw_list.draw_list,
1657                    center,
1658                    self.radius,
1659                    self.color.into(),
1660                    self.num_segments,
1661                    self.thickness,
1662                )
1663            }
1664        }
1665    }
1666}
1667
1668/// Represents a Bezier curve about to be drawn
1669#[must_use = "should call .build() to draw the object"]
1670pub struct BezierCurve<'ui> {
1671    pos0: [f32; 2],
1672    cp0: [f32; 2],
1673    pos1: [f32; 2],
1674    cp1: [f32; 2],
1675    color: ImColor32,
1676    thickness: f32,
1677    /// If num_segments is not set, the bezier curve is auto-tessalated.
1678    num_segments: Option<u32>,
1679    draw_list: &'ui DrawListMut<'ui>,
1680}
1681
1682impl<'ui> BezierCurve<'ui> {
1683    /// Typically constructed by [`DrawListMut::add_bezier_curve`]
1684    pub fn new<C>(
1685        draw_list: &'ui DrawListMut<'_>,
1686        pos0: impl Into<sys::ImVec2>,
1687        cp0: impl Into<sys::ImVec2>,
1688        cp1: impl Into<sys::ImVec2>,
1689        pos1: impl Into<sys::ImVec2>,
1690        c: C,
1691    ) -> Self
1692    where
1693        C: Into<ImColor32>,
1694    {
1695        Self {
1696            pos0: {
1697                let v: sys::ImVec2 = pos0.into();
1698                v.into()
1699            },
1700            cp0: {
1701                let v: sys::ImVec2 = cp0.into();
1702                v.into()
1703            },
1704            cp1: {
1705                let v: sys::ImVec2 = cp1.into();
1706                v.into()
1707            },
1708            pos1: {
1709                let v: sys::ImVec2 = pos1.into();
1710                v.into()
1711            },
1712            color: c.into(),
1713            thickness: 1.0,
1714            num_segments: None,
1715            draw_list,
1716        }
1717    }
1718
1719    /// Set curve's thickness (default to 1.0 pixel)
1720    pub fn thickness(mut self, thickness: f32) -> Self {
1721        self.thickness = thickness;
1722        self
1723    }
1724
1725    /// Set number of segments used to draw the Bezier curve. If not set, the
1726    /// bezier curve is auto-tessalated.
1727    pub fn num_segments(mut self, num_segments: u32) -> Self {
1728        self.num_segments = Some(num_segments);
1729        self
1730    }
1731
1732    /// Draw the curve on the window.
1733    pub fn build(self) {
1734        unsafe {
1735            let pos0: sys::ImVec2 = self.pos0.into();
1736            let cp0: sys::ImVec2 = self.cp0.into();
1737            let cp1: sys::ImVec2 = self.cp1.into();
1738            let pos1: sys::ImVec2 = self.pos1.into();
1739
1740            sys::ImDrawList_AddBezierCubic(
1741                self.draw_list.draw_list,
1742                pos0,
1743                cp0,
1744                cp1,
1745                pos1,
1746                self.color.into(),
1747                self.thickness,
1748                self.num_segments.unwrap_or(0) as i32,
1749            )
1750        }
1751    }
1752}
1753
1754/// Represents a poly line about to be drawn
1755#[must_use = "should call .build() to draw the object"]
1756pub struct Polyline<'ui> {
1757    points: Vec<[f32; 2]>,
1758    thickness: f32,
1759    filled: bool,
1760    color: ImColor32,
1761    draw_list: &'ui DrawListMut<'ui>,
1762}
1763
1764impl<'ui> Polyline<'ui> {
1765    fn new<C, P>(draw_list: &'ui DrawListMut<'_>, points: Vec<P>, c: C) -> Self
1766    where
1767        C: Into<ImColor32>,
1768        P: Into<sys::ImVec2>,
1769    {
1770        Self {
1771            points: points
1772                .into_iter()
1773                .map(|p| {
1774                    let v: sys::ImVec2 = p.into();
1775                    v.into()
1776                })
1777                .collect(),
1778            color: c.into(),
1779            thickness: 1.0,
1780            filled: false,
1781            draw_list,
1782        }
1783    }
1784
1785    /// Set line's thickness (default to 1.0 pixel). Has no effect if
1786    /// shape is filled
1787    pub fn thickness(mut self, thickness: f32) -> Self {
1788        self.thickness = thickness;
1789        self
1790    }
1791
1792    /// Draw shape as filled convex polygon
1793    pub fn filled(mut self, filled: bool) -> Self {
1794        self.filled = filled;
1795        self
1796    }
1797
1798    /// Draw the line on the window
1799    pub fn build(self) {
1800        if self.filled {
1801            unsafe {
1802                sys::ImDrawList_AddConvexPolyFilled(
1803                    self.draw_list.draw_list,
1804                    self.points.as_ptr() as *const sys::ImVec2,
1805                    self.points.len() as i32,
1806                    self.color.into(),
1807                )
1808            }
1809        } else {
1810            unsafe {
1811                sys::ImDrawList_AddPolyline(
1812                    self.draw_list.draw_list,
1813                    self.points.as_ptr() as *const sys::ImVec2,
1814                    self.points.len() as i32,
1815                    self.color.into(),
1816                    sys::ImDrawFlags::default(),
1817                    self.thickness,
1818                )
1819            }
1820        }
1821    }
1822}
1823
1824/// Represents a triangle about to be drawn on the window
1825#[must_use = "should call .build() to draw the object"]
1826pub struct Triangle<'ui> {
1827    p1: [f32; 2],
1828    p2: [f32; 2],
1829    p3: [f32; 2],
1830    color: ImColor32,
1831    thickness: f32,
1832    filled: bool,
1833    draw_list: &'ui DrawListMut<'ui>,
1834}
1835
1836impl<'ui> Triangle<'ui> {
1837    fn new<C>(
1838        draw_list: &'ui DrawListMut<'_>,
1839        p1: impl Into<sys::ImVec2>,
1840        p2: impl Into<sys::ImVec2>,
1841        p3: impl Into<sys::ImVec2>,
1842        c: C,
1843    ) -> Self
1844    where
1845        C: Into<ImColor32>,
1846    {
1847        Self {
1848            p1: {
1849                let v: sys::ImVec2 = p1.into();
1850                v.into()
1851            },
1852            p2: {
1853                let v: sys::ImVec2 = p2.into();
1854                v.into()
1855            },
1856            p3: {
1857                let v: sys::ImVec2 = p3.into();
1858                v.into()
1859            },
1860            color: c.into(),
1861            thickness: 1.0,
1862            filled: false,
1863            draw_list,
1864        }
1865    }
1866
1867    /// Set triangle's thickness (default to 1.0 pixel)
1868    pub fn thickness(mut self, thickness: f32) -> Self {
1869        self.thickness = thickness;
1870        self
1871    }
1872
1873    /// Set to `true` to make a filled triangle (default to `false`).
1874    pub fn filled(mut self, filled: bool) -> Self {
1875        self.filled = filled;
1876        self
1877    }
1878
1879    /// Draw the triangle on the window.
1880    pub fn build(self) {
1881        let p1 = sys::ImVec2 {
1882            x: self.p1[0],
1883            y: self.p1[1],
1884        };
1885        let p2 = sys::ImVec2 {
1886            x: self.p2[0],
1887            y: self.p2[1],
1888        };
1889        let p3 = sys::ImVec2 {
1890            x: self.p3[0],
1891            y: self.p3[1],
1892        };
1893
1894        if self.filled {
1895            unsafe {
1896                sys::ImDrawList_AddTriangleFilled(
1897                    self.draw_list.draw_list,
1898                    p1,
1899                    p2,
1900                    p3,
1901                    self.color.into(),
1902                )
1903            }
1904        } else {
1905            unsafe {
1906                sys::ImDrawList_AddTriangle(
1907                    self.draw_list.draw_list,
1908                    p1,
1909                    p2,
1910                    p3,
1911                    self.color.into(),
1912                    self.thickness,
1913                )
1914            }
1915        }
1916    }
1917}