arcdps_imgui/
draw_list.rs

1//! The draw list lets you create custom graphics within a window.
2//!
3//! Each dear imgui window contains its own draw list. You can use
4//! [`Ui::get_window_draw_list`] to access the current window draw
5//! list and draw custom primitives. You can interleave normal widget
6//! calls and adding primitives to the current draw list.
7//!
8//! Interaction is mostly through the mtehods [`DrawListMut`] struct,
9//! such as [`DrawListMut::add_line`], however you can also construct
10//!  structs like [`Line`] directly, then call
11//!  `Line::build` with a reference to your draw list
12//!
13//! There are examples such as `draw_list.rs` and `custom_textures.rs`
14//! within the `imgui-examples` directory
15
16use bitflags::bitflags;
17
18use crate::ImColor32;
19use sys::ImDrawList;
20
21use super::Ui;
22use crate::render::renderer::TextureId;
23
24use std::marker::PhantomData;
25
26bitflags!(
27    /// Draw list flags
28    #[repr(C)]
29    pub struct DrawListFlags: u32 {
30        const NONE = sys::ImDrawListFlags_None;
31        /// Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines
32        /// thin enough to be drawn using textures, otherwise *3 the number of triangles)
33        const ANTI_ALIASED_LINES = sys::ImDrawListFlags_AntiAliasedLines;
34        /// Enable anti-aliased lines/borders using textures when possible. Require backend to render
35        /// with bilinear filtering.
36        const ANTI_ALIASED_LINES_USE_TEX = sys::ImDrawListFlags_AntiAliasedLinesUseTex;
37        /// Enable anti-aliased edge around filled shapes (rounded rectangles, circles).
38        const ANTI_ALIASED_FILL = sys::ImDrawListFlags_AntiAliasedFill;
39        /// Can emit 'VtxOffset > 0' to allow large meshes. Set when
40        /// [`BackendFlags::RENDERER_HAS_VTX_OFFSET`] is enabled.
41        const ALLOW_VTX_OFFSET = sys::ImDrawListFlags_AllowVtxOffset;
42    }
43);
44
45enum DrawListType {
46    Window,
47    Background,
48    Foreground,
49}
50
51/// Object implementing the custom draw API.
52///
53/// Called from [`Ui::get_window_draw_list`], [`Ui::get_background_draw_list`] or [`Ui::get_foreground_draw_list`].
54/// No more than one instance of this structure can live in a program at the same time.
55/// The program will panic on creating a second instance.
56pub struct DrawListMut<'ui> {
57    draw_list_type: DrawListType,
58    draw_list: *mut ImDrawList,
59    _phantom: PhantomData<&'ui Ui<'ui>>,
60}
61
62// Lock for each variant of draw list. See https://github.com/imgui-rs/imgui-rs/issues/488
63static DRAW_LIST_LOADED_WINDOW: std::sync::atomic::AtomicBool =
64    std::sync::atomic::AtomicBool::new(false);
65static DRAW_LIST_LOADED_BACKGROUND: std::sync::atomic::AtomicBool =
66    std::sync::atomic::AtomicBool::new(false);
67static DRAW_LIST_LOADED_FOREGROUND: std::sync::atomic::AtomicBool =
68    std::sync::atomic::AtomicBool::new(false);
69
70impl<'ui> Drop for DrawListMut<'ui> {
71    fn drop(&mut self) {
72        match self.draw_list_type {
73            DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
74            DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
75            DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
76        }
77        .store(false, std::sync::atomic::Ordering::Release);
78    }
79}
80
81impl<'ui> DrawListMut<'ui> {
82    fn lock_draw_list(t: DrawListType) {
83        let lock = match t {
84            DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
85            DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
86            DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
87        };
88
89        let already_loaded = lock
90            .compare_exchange(
91                false,
92                true,
93                std::sync::atomic::Ordering::Acquire,
94                std::sync::atomic::Ordering::Relaxed,
95            )
96            .is_err();
97        if already_loaded {
98            let name = match t {
99                DrawListType::Window => "window",
100                DrawListType::Background => "background",
101                DrawListType::Foreground => "foreground",
102            };
103            panic!("The DrawListMut instance for the {} draw list is already loaded! You can only load one instance of it!", name)
104        }
105    }
106
107    #[doc(alias = "GetWindowDrawList")]
108    pub(crate) fn window(_: &Ui<'ui>) -> Self {
109        Self::lock_draw_list(DrawListType::Window);
110
111        Self {
112            draw_list: unsafe { sys::igGetWindowDrawList() },
113            draw_list_type: DrawListType::Window,
114            _phantom: PhantomData,
115        }
116    }
117
118    #[doc(alias = "GetBackgroundDrawList")]
119    pub(crate) fn background(_: &Ui<'ui>) -> Self {
120        Self::lock_draw_list(DrawListType::Background);
121        Self {
122            draw_list: unsafe { sys::igGetBackgroundDrawList() },
123            draw_list_type: DrawListType::Background,
124            _phantom: PhantomData,
125        }
126    }
127
128    #[doc(alias = "GetForegroundDrawList")]
129    pub(crate) fn foreground(_: &Ui<'ui>) -> Self {
130        Self::lock_draw_list(DrawListType::Foreground);
131        Self {
132            draw_list: unsafe { sys::igGetForegroundDrawList() },
133            draw_list_type: DrawListType::Foreground,
134            _phantom: PhantomData,
135        }
136    }
137
138    /// Split into *channels_count* drawing channels.
139    /// At the end of the closure, the channels are merged. The objects
140    /// are then drawn in the increasing order of their channel number, and not
141    /// in the order they were called.
142    ///
143    /// # Example
144    ///
145    /// ```rust,no_run
146    /// # use arcdps_imgui::*;
147    /// fn custom_drawing(ui: &Ui) {
148    ///     let draw_list = ui.get_window_draw_list();
149    ///     draw_list.channels_split(2, |channels| {
150    ///         channels.set_current(1);
151    ///         // ... Draw channel 1
152    ///         channels.set_current(0);
153    ///         // ... Draw channel 0
154    ///     });
155    /// }
156    /// ```
157    #[doc(alias = "ChannelsSplit")]
158    pub fn channels_split<F: FnOnce(&ChannelsSplit<'_>)>(&self, channels_count: u32, f: F) {
159        unsafe { sys::ImDrawList_ChannelsSplit(self.draw_list, channels_count as i32) };
160        f(&ChannelsSplit {
161            draw_list: self,
162            channels_count,
163        });
164        unsafe { sys::ImDrawList_ChannelsMerge(self.draw_list) };
165    }
166}
167
168/// Represent the drawing interface within a call to [`channels_split`].
169///
170/// [`channels_split`]: DrawListMut::channels_split
171pub struct ChannelsSplit<'ui> {
172    draw_list: &'ui DrawListMut<'ui>,
173    channels_count: u32,
174}
175
176impl<'ui> ChannelsSplit<'ui> {
177    /// Change current channel.
178    ///
179    /// Panic if channel_index overflows the number of channels.
180    #[doc(alias = "ChannelsSetCurrent")]
181    pub fn set_current(&self, channel_index: u32) {
182        assert!(
183            channel_index < self.channels_count,
184            "Channel cannot be set! Provided channel index ({}) is higher than channel count ({}).",
185            channel_index,
186            self.channels_count
187        );
188        unsafe {
189            sys::ImDrawList_ChannelsSetCurrent(self.draw_list.draw_list, channel_index as i32)
190        };
191    }
192}
193
194/// Drawing functions
195impl<'ui> DrawListMut<'ui> {
196    /// Returns a line from point `p1` to `p2` with color `c`.
197    #[doc(alias = "AddLine")]
198    pub fn add_line<C>(&'ui self, p1: [f32; 2], p2: [f32; 2], c: C) -> Line<'ui>
199    where
200        C: Into<ImColor32>,
201    {
202        Line::new(self, p1, p2, c)
203    }
204
205    /// Returns a rectangle whose upper-left corner is at point `p1`
206    /// and lower-right corner is at point `p2`, with color `c`.
207    #[doc(alias = "AddRectFilled", alias = "AddRect")]
208    pub fn add_rect<C>(&'ui self, p1: [f32; 2], p2: [f32; 2], c: C) -> Rect<'ui>
209    where
210        C: Into<ImColor32>,
211    {
212        Rect::new(self, p1, p2, c)
213    }
214
215    /// Draw a rectangle whose upper-left corner is at point `p1`
216    /// and lower-right corner is at point `p2`.
217    /// The remains parameters are the respective color of the corners
218    /// in the counter-clockwise starting from the upper-left corner
219    /// first.
220    #[doc(alias = "AddRectFilledMultiColor")]
221    pub fn add_rect_filled_multicolor<C1, C2, C3, C4>(
222        &self,
223        p1: [f32; 2],
224        p2: [f32; 2],
225        col_upr_left: C1,
226        col_upr_right: C2,
227        col_bot_right: C3,
228        col_bot_left: C4,
229    ) where
230        C1: Into<ImColor32>,
231        C2: Into<ImColor32>,
232        C3: Into<ImColor32>,
233        C4: Into<ImColor32>,
234    {
235        unsafe {
236            sys::ImDrawList_AddRectFilledMultiColor(
237                self.draw_list,
238                p1.into(),
239                p2.into(),
240                col_upr_left.into().into(),
241                col_upr_right.into().into(),
242                col_bot_right.into().into(),
243                col_bot_left.into().into(),
244            );
245        }
246    }
247
248    /// Returns a triangle with the given 3 vertices `p1`, `p2` and `p3`
249    /// and color `c`.
250    #[doc(alias = "AddTriangleFilled", alias = "AddTriangle")]
251    pub fn add_triangle<C>(
252        &'ui self,
253        p1: [f32; 2],
254        p2: [f32; 2],
255        p3: [f32; 2],
256        c: C,
257    ) -> Triangle<'ui>
258    where
259        C: Into<ImColor32>,
260    {
261        Triangle::new(self, p1, p2, p3, c)
262    }
263
264    /// Returns a circle with the given `center`, `radius` and `color`.
265    #[doc(alias = "AddCircleFilled", alias = "AddCircle")]
266    pub fn add_circle<C>(&'ui self, center: [f32; 2], radius: f32, color: C) -> Circle<'ui>
267    where
268        C: Into<ImColor32>,
269    {
270        Circle::new(self, center, radius, color)
271    }
272
273    /// Draw a text whose upper-left corner is at point `pos`.
274    #[doc(alias = "AddText")]
275    pub fn add_text<C, T>(&self, pos: [f32; 2], col: C, text: T)
276    where
277        C: Into<ImColor32>,
278        T: AsRef<str>,
279    {
280        use std::os::raw::c_char;
281
282        let text = text.as_ref();
283        unsafe {
284            let start = text.as_ptr() as *const c_char;
285            let end = (start as usize + text.len()) as *const c_char;
286            sys::ImDrawList_AddText_Vec2(self.draw_list, pos.into(), col.into().into(), start, end)
287        }
288    }
289
290    /// Returns a Bezier curve stretching from `pos0` to `pos1`, whose
291    /// curvature is defined by `cp0` and `cp1`.
292    #[doc(alias = "AddBezier", alias = "AddBezierCubic")]
293    pub fn add_bezier_curve<C>(
294        &'ui self,
295        pos0: [f32; 2],
296        cp0: [f32; 2],
297        cp1: [f32; 2],
298        pos1: [f32; 2],
299        color: C,
300    ) -> BezierCurve<'ui>
301    where
302        C: Into<ImColor32>,
303    {
304        BezierCurve::new(self, pos0, cp0, cp1, pos1, color)
305    }
306
307    /// Push a clipping rectangle on the stack, run `f` and pop it.
308    ///
309    /// Clip all drawings done within the closure `f` in the given
310    /// rectangle.
311    #[doc(alias = "PushClipRect", alias = "PopClipRect")]
312    pub fn with_clip_rect<F>(&self, min: [f32; 2], max: [f32; 2], f: F)
313    where
314        F: FnOnce(),
315    {
316        unsafe { sys::ImDrawList_PushClipRect(self.draw_list, min.into(), max.into(), false) }
317        f();
318        unsafe { sys::ImDrawList_PopClipRect(self.draw_list) }
319    }
320
321    /// Push a clipping rectangle on the stack, run `f` and pop it.
322    ///
323    /// Clip all drawings done within the closure `f` in the given
324    /// rectangle. Intersect with all clipping rectangle previously on
325    /// the stack.
326    #[doc(alias = "PushClipRect", alias = "PopClipRect")]
327    pub fn with_clip_rect_intersect<F>(&self, min: [f32; 2], max: [f32; 2], f: F)
328    where
329        F: FnOnce(),
330    {
331        unsafe { sys::ImDrawList_PushClipRect(self.draw_list, min.into(), max.into(), true) }
332        f();
333        unsafe { sys::ImDrawList_PopClipRect(self.draw_list) }
334    }
335}
336
337/// # Images
338impl<'ui> DrawListMut<'ui> {
339    /// Draw the specified image in the rect specified by `p_min` to
340    /// `p_max`.
341    ///
342    /// # Examples
343    ///
344    /// ```
345    /// # use arcdps_imgui::*;
346    /// fn custom_button(ui: &Ui, img_id: TextureId) {
347    ///     // Invisible button is good widget to customise with image
348    ///     ui.invisible_button(im_str!("custom_button"), [100.0, 20.0]);
349    ///
350    ///     // Get draw list and draw image over invisible button
351    ///     let draw_list = ui.get_window_draw_list();
352    ///     draw_list
353    ///         .add_image(img_id, ui.item_rect_min(), ui.item_rect_max())
354    ///         .build();
355    /// }
356    /// ```
357    pub fn add_image(
358        &'ui self,
359        texture_id: TextureId,
360        p_min: [f32; 2],
361        p_max: [f32; 2],
362    ) -> Image<'_> {
363        Image::new(self, texture_id, p_min, p_max)
364    }
365
366    /// Draw the specified image to a quad with the specified
367    /// coordinates. Similar to [`DrawListMut::add_image`] but this
368    /// method is able to draw non-rectangle images.
369    pub fn add_image_quad(
370        &'ui self,
371        texture_id: TextureId,
372        p1: [f32; 2],
373        p2: [f32; 2],
374        p3: [f32; 2],
375        p4: [f32; 2],
376    ) -> ImageQuad<'_> {
377        ImageQuad::new(self, texture_id, p1, p2, p3, p4)
378    }
379
380    /// Draw the speciied image, with rounded corners
381    pub fn add_image_rounded(
382        &'ui self,
383        texture_id: TextureId,
384        p_min: [f32; 2],
385        p_max: [f32; 2],
386        rounding: f32,
387    ) -> ImageRounded<'_> {
388        ImageRounded::new(self, texture_id, p_min, p_max, rounding)
389    }
390}
391
392/// Represents a line about to be drawn
393#[must_use = "should call .build() to draw the object"]
394pub struct Line<'ui> {
395    p1: [f32; 2],
396    p2: [f32; 2],
397    color: ImColor32,
398    thickness: f32,
399    draw_list: &'ui DrawListMut<'ui>,
400}
401
402impl<'ui> Line<'ui> {
403    fn new<C>(draw_list: &'ui DrawListMut<'_>, p1: [f32; 2], p2: [f32; 2], c: C) -> Self
404    where
405        C: Into<ImColor32>,
406    {
407        Self {
408            p1,
409            p2,
410            color: c.into(),
411            thickness: 1.0,
412            draw_list,
413        }
414    }
415
416    /// Set line's thickness (default to 1.0 pixel)
417    pub fn thickness(mut self, thickness: f32) -> Self {
418        self.thickness = thickness;
419        self
420    }
421
422    /// Draw the line on the window
423    pub fn build(self) {
424        unsafe {
425            sys::ImDrawList_AddLine(
426                self.draw_list.draw_list,
427                self.p1.into(),
428                self.p2.into(),
429                self.color.into(),
430                self.thickness,
431            )
432        }
433    }
434}
435
436bitflags!(
437    /// Flags for indicating which corner of a rectangle should be rounded
438    #[repr(C)]
439    pub struct ImDrawCornerFlags: u32 {
440        const TOP_LEFT = 1;
441        const TOP_RIGHT = 1 << 1;
442        const BOT_LEFT = 1 << 2;
443        const BOT_RIGHT = 1 << 3;
444        const TOP = ImDrawCornerFlags::TOP_LEFT.bits
445            | ImDrawCornerFlags::TOP_RIGHT.bits;
446        const BOT = ImDrawCornerFlags::BOT_LEFT.bits
447            | ImDrawCornerFlags::BOT_RIGHT.bits;
448        const LEFT = ImDrawCornerFlags::TOP_LEFT.bits
449            | ImDrawCornerFlags::BOT_LEFT.bits;
450        const RIGHT = ImDrawCornerFlags::TOP_RIGHT.bits
451            | ImDrawCornerFlags::BOT_RIGHT.bits;
452        const ALL = 0xF;
453    }
454);
455
456/// Represents a rectangle about to be drawn
457#[must_use = "should call .build() to draw the object"]
458pub struct Rect<'ui> {
459    p1: [f32; 2],
460    p2: [f32; 2],
461    color: ImColor32,
462    rounding: f32,
463    flags: ImDrawCornerFlags,
464    thickness: f32,
465    filled: bool,
466    draw_list: &'ui DrawListMut<'ui>,
467}
468
469impl<'ui> Rect<'ui> {
470    fn new<C>(draw_list: &'ui DrawListMut<'_>, p1: [f32; 2], p2: [f32; 2], c: C) -> Self
471    where
472        C: Into<ImColor32>,
473    {
474        Self {
475            p1,
476            p2,
477            color: c.into(),
478            rounding: 0.0,
479            flags: ImDrawCornerFlags::ALL,
480            thickness: 1.0,
481            filled: false,
482            draw_list,
483        }
484    }
485
486    /// Set rectangle's corner rounding (default to 0.0: no rounding).
487    /// By default all corners are rounded if this value is set.
488    pub fn rounding(mut self, rounding: f32) -> Self {
489        self.rounding = rounding;
490        self
491    }
492
493    /// Set flag to indicate if rectangle's top-left corner will be rounded.
494    pub fn round_top_left(mut self, value: bool) -> Self {
495        self.flags.set(ImDrawCornerFlags::TOP_LEFT, value);
496        self
497    }
498
499    /// Set flag to indicate if rectangle's top-right corner will be rounded.
500    pub fn round_top_right(mut self, value: bool) -> Self {
501        self.flags.set(ImDrawCornerFlags::TOP_RIGHT, value);
502        self
503    }
504
505    /// Set flag to indicate if rectangle's bottom-left corner will be rounded.
506    pub fn round_bot_left(mut self, value: bool) -> Self {
507        self.flags.set(ImDrawCornerFlags::BOT_LEFT, value);
508        self
509    }
510
511    /// Set flag to indicate if rectangle's bottom-right corner will be rounded.
512    pub fn round_bot_right(mut self, value: bool) -> Self {
513        self.flags.set(ImDrawCornerFlags::BOT_RIGHT, value);
514        self
515    }
516
517    /// Set rectangle's thickness (default to 1.0 pixel).
518    pub fn thickness(mut self, thickness: f32) -> Self {
519        self.thickness = thickness;
520        self
521    }
522
523    /// Set to `true` to make a filled rectangle (default to `false`).
524    pub fn filled(mut self, filled: bool) -> Self {
525        self.filled = filled;
526        self
527    }
528
529    /// Draw the rectangle on the window.
530    pub fn build(self) {
531        if self.filled {
532            unsafe {
533                sys::ImDrawList_AddRectFilled(
534                    self.draw_list.draw_list,
535                    self.p1.into(),
536                    self.p2.into(),
537                    self.color.into(),
538                    self.rounding,
539                    self.flags.bits() as i32,
540                );
541            }
542        } else {
543            unsafe {
544                sys::ImDrawList_AddRect(
545                    self.draw_list.draw_list,
546                    self.p1.into(),
547                    self.p2.into(),
548                    self.color.into(),
549                    self.rounding,
550                    self.flags.bits() as i32,
551                    self.thickness,
552                );
553            }
554        }
555    }
556}
557
558/// Represents a triangle about to be drawn on the window
559#[must_use = "should call .build() to draw the object"]
560pub struct Triangle<'ui> {
561    p1: [f32; 2],
562    p2: [f32; 2],
563    p3: [f32; 2],
564    color: ImColor32,
565    thickness: f32,
566    filled: bool,
567    draw_list: &'ui DrawListMut<'ui>,
568}
569
570impl<'ui> Triangle<'ui> {
571    fn new<C>(
572        draw_list: &'ui DrawListMut<'_>,
573        p1: [f32; 2],
574        p2: [f32; 2],
575        p3: [f32; 2],
576        c: C,
577    ) -> Self
578    where
579        C: Into<ImColor32>,
580    {
581        Self {
582            p1,
583            p2,
584            p3,
585            color: c.into(),
586            thickness: 1.0,
587            filled: false,
588            draw_list,
589        }
590    }
591
592    /// Set triangle's thickness (default to 1.0 pixel)
593    pub fn thickness(mut self, thickness: f32) -> Self {
594        self.thickness = thickness;
595        self
596    }
597
598    /// Set to `true` to make a filled triangle (default to `false`).
599    pub fn filled(mut self, filled: bool) -> Self {
600        self.filled = filled;
601        self
602    }
603
604    /// Draw the triangle on the window.
605    pub fn build(self) {
606        if self.filled {
607            unsafe {
608                sys::ImDrawList_AddTriangleFilled(
609                    self.draw_list.draw_list,
610                    self.p1.into(),
611                    self.p2.into(),
612                    self.p3.into(),
613                    self.color.into(),
614                )
615            }
616        } else {
617            unsafe {
618                sys::ImDrawList_AddTriangle(
619                    self.draw_list.draw_list,
620                    self.p1.into(),
621                    self.p2.into(),
622                    self.p3.into(),
623                    self.color.into(),
624                    self.thickness,
625                )
626            }
627        }
628    }
629}
630
631/// Represents a circle about to be drawn
632#[must_use = "should call .build() to draw the object"]
633pub struct Circle<'ui> {
634    center: [f32; 2],
635    radius: f32,
636    color: ImColor32,
637    num_segments: u32,
638    thickness: f32,
639    filled: bool,
640    draw_list: &'ui DrawListMut<'ui>,
641}
642
643impl<'ui> Circle<'ui> {
644    /// Typically constructed by [`DrawListMut::add_circle`]
645    pub fn new<C>(draw_list: &'ui DrawListMut<'_>, center: [f32; 2], radius: f32, color: C) -> Self
646    where
647        C: Into<ImColor32>,
648    {
649        Self {
650            center,
651            radius,
652            color: color.into(),
653            num_segments: 0,
654            thickness: 1.0,
655            filled: false,
656            draw_list,
657        }
658    }
659
660    /// Set number of segment used to draw the circle, default to 0.
661    /// Add more segments if you want a smoother circle.
662    pub fn num_segments(mut self, num_segments: u32) -> Self {
663        self.num_segments = num_segments;
664        self
665    }
666
667    /// Set circle's thickness (default to 1.0 pixel)
668    pub fn thickness(mut self, thickness: f32) -> Self {
669        self.thickness = thickness;
670        self
671    }
672
673    /// Set to `true` to make a filled circle (default to `false`).
674    pub fn filled(mut self, filled: bool) -> Self {
675        self.filled = filled;
676        self
677    }
678
679    /// Draw the circle on the window.
680    pub fn build(self) {
681        if self.filled {
682            unsafe {
683                sys::ImDrawList_AddCircleFilled(
684                    self.draw_list.draw_list,
685                    self.center.into(),
686                    self.radius,
687                    self.color.into(),
688                    self.num_segments as i32,
689                )
690            }
691        } else {
692            unsafe {
693                sys::ImDrawList_AddCircle(
694                    self.draw_list.draw_list,
695                    self.center.into(),
696                    self.radius,
697                    self.color.into(),
698                    self.num_segments as i32,
699                    self.thickness,
700                )
701            }
702        }
703    }
704}
705
706/// Represents a Bezier curve about to be drawn
707#[must_use = "should call .build() to draw the object"]
708pub struct BezierCurve<'ui> {
709    pos0: [f32; 2],
710    cp0: [f32; 2],
711    pos1: [f32; 2],
712    cp1: [f32; 2],
713    color: ImColor32,
714    thickness: f32,
715    /// If num_segments is not set, the bezier curve is auto-tessalated.
716    num_segments: Option<u32>,
717    draw_list: &'ui DrawListMut<'ui>,
718}
719
720impl<'ui> BezierCurve<'ui> {
721    /// Typically constructed by [`DrawListMut::add_bezier_curve`]
722    pub fn new<C>(
723        draw_list: &'ui DrawListMut<'_>,
724        pos0: [f32; 2],
725        cp0: [f32; 2],
726        cp1: [f32; 2],
727        pos1: [f32; 2],
728        c: C,
729    ) -> Self
730    where
731        C: Into<ImColor32>,
732    {
733        Self {
734            pos0,
735            cp0,
736            cp1,
737            pos1,
738            color: c.into(),
739            thickness: 1.0,
740            num_segments: None,
741            draw_list,
742        }
743    }
744
745    /// Set curve's thickness (default to 1.0 pixel)
746    pub fn thickness(mut self, thickness: f32) -> Self {
747        self.thickness = thickness;
748        self
749    }
750
751    /// Set number of segments used to draw the Bezier curve. If not set, the
752    /// bezier curve is auto-tessalated.
753    pub fn num_segments(mut self, num_segments: u32) -> Self {
754        self.num_segments = Some(num_segments);
755        self
756    }
757
758    /// Draw the curve on the window.
759    pub fn build(self) {
760        unsafe {
761            sys::ImDrawList_AddBezierCubic(
762                self.draw_list.draw_list,
763                self.pos0.into(),
764                self.cp0.into(),
765                self.cp1.into(),
766                self.pos1.into(),
767                self.color.into(),
768                self.thickness,
769                self.num_segments.unwrap_or(0) as i32,
770            )
771        }
772    }
773}
774
775/// Image draw list primitive, not to be confused with the widget
776/// [`imgui::Image`](crate::Image).
777#[must_use = "should call .build() to draw the object"]
778pub struct Image<'ui> {
779    texture_id: TextureId,
780    p_min: [f32; 2],
781    p_max: [f32; 2],
782    uv_min: [f32; 2],
783    uv_max: [f32; 2],
784    col: ImColor32,
785    draw_list: &'ui DrawListMut<'ui>,
786}
787
788impl<'ui> Image<'ui> {
789    /// Typically constructed by [`DrawListMut::add_image`]
790    pub fn new(
791        draw_list: &'ui DrawListMut<'_>,
792        texture_id: TextureId,
793        p_min: [f32; 2],
794        p_max: [f32; 2],
795    ) -> Self {
796        Self {
797            texture_id,
798            p_min,
799            p_max,
800            uv_min: [0.0, 0.0],
801            uv_max: [1.0, 1.0],
802            col: [1.0, 1.0, 1.0, 1.0].into(),
803            draw_list,
804        }
805    }
806
807    /// Set uv_min (default `[0.0, 0.0]`)
808    pub fn uv_min(mut self, uv_min: [f32; 2]) -> Self {
809        self.uv_min = uv_min;
810        self
811    }
812    /// Set uv_max (default `[1.0, 1.0]`)
813    pub fn uv_max(mut self, uv_max: [f32; 2]) -> Self {
814        self.uv_max = uv_max;
815        self
816    }
817
818    /// Set color tint (default: no tint/white `[1.0, 1.0, 1.0, 1.0]`)
819    pub fn col<C>(mut self, col: C) -> Self
820    where
821        C: Into<ImColor32>,
822    {
823        self.col = col.into();
824        self
825    }
826
827    /// Draw the image on the window.
828    pub fn build(self) {
829        use std::os::raw::c_void;
830
831        unsafe {
832            sys::ImDrawList_AddImage(
833                self.draw_list.draw_list,
834                self.texture_id.id() as *mut c_void,
835                self.p_min.into(),
836                self.p_max.into(),
837                self.uv_min.into(),
838                self.uv_max.into(),
839                self.col.into(),
840            );
841        }
842    }
843}
844
845/// Represents a image about to be drawn
846#[must_use = "should call .build() to draw the object"]
847pub struct ImageQuad<'ui> {
848    texture_id: TextureId,
849    p1: [f32; 2],
850    p2: [f32; 2],
851    p3: [f32; 2],
852    p4: [f32; 2],
853    uv1: [f32; 2],
854    uv2: [f32; 2],
855    uv3: [f32; 2],
856    uv4: [f32; 2],
857    col: ImColor32,
858    draw_list: &'ui DrawListMut<'ui>,
859}
860
861impl<'ui> ImageQuad<'ui> {
862    /// Typically constructed by [`DrawListMut::add_image_quad`]
863    pub fn new(
864        draw_list: &'ui DrawListMut<'_>,
865        texture_id: TextureId,
866        p1: [f32; 2],
867        p2: [f32; 2],
868        p3: [f32; 2],
869        p4: [f32; 2],
870    ) -> Self {
871        Self {
872            texture_id,
873            p1,
874            p2,
875            p3,
876            p4,
877            uv1: [0.0, 0.0],
878            uv2: [1.0, 0.0],
879            uv3: [1.0, 1.0],
880            uv4: [0.0, 1.0],
881            col: [1.0, 1.0, 1.0, 1.0].into(),
882            draw_list,
883        }
884    }
885
886    /// Set uv coordinates of each point of the quad. If not called, defaults are:
887    ///
888    /// ```text
889    /// uv1: [0.0, 0.0],
890    /// uv2: [1, 0],
891    /// uv3: [1, 1],
892    /// uv4: [0, 1],
893    /// ```
894    pub fn uv(mut self, uv1: [f32; 2], uv2: [f32; 2], uv3: [f32; 2], uv4: [f32; 2]) -> Self {
895        self.uv1 = uv1;
896        self.uv2 = uv2;
897        self.uv3 = uv3;
898        self.uv4 = uv4;
899        self
900    }
901
902    /// Set color tint (default: no tint/white `[1.0, 1.0, 1.0, 1.0]`)
903    pub fn col<C>(mut self, col: C) -> Self
904    where
905        C: Into<ImColor32>,
906    {
907        self.col = col.into();
908        self
909    }
910
911    /// Draw the image on the window.
912    pub fn build(self) {
913        use std::os::raw::c_void;
914
915        unsafe {
916            sys::ImDrawList_AddImageQuad(
917                self.draw_list.draw_list,
918                self.texture_id.id() as *mut c_void,
919                self.p1.into(),
920                self.p2.into(),
921                self.p3.into(),
922                self.p4.into(),
923                self.uv1.into(),
924                self.uv2.into(),
925                self.uv3.into(),
926                self.uv4.into(),
927                self.col.into(),
928            );
929        }
930    }
931}
932
933/// Represents a image about to be drawn. Similar to [`Image`] but
934/// with corners rounded with a given radius
935#[must_use = "should call .build() to draw the object"]
936pub struct ImageRounded<'ui> {
937    texture_id: TextureId,
938    p_min: [f32; 2],
939    p_max: [f32; 2],
940    uv_min: [f32; 2],
941    uv_max: [f32; 2],
942    col: ImColor32,
943    rounding: f32,
944    draw_flags: ImDrawCornerFlags,
945    draw_list: &'ui DrawListMut<'ui>,
946}
947
948impl<'ui> ImageRounded<'ui> {
949    /// Typically constructed by [`DrawListMut::add_image_rounded`]
950    pub fn new(
951        draw_list: &'ui DrawListMut<'_>,
952        texture_id: TextureId,
953        p_min: [f32; 2],
954        p_max: [f32; 2],
955        rounding: f32,
956    ) -> Self {
957        Self {
958            texture_id,
959            p_min,
960            p_max,
961            uv_min: [0.0, 0.0],
962            uv_max: [1.0, 1.0],
963            col: [1.0, 1.0, 1.0, 1.0].into(),
964            rounding,
965            draw_flags: ImDrawCornerFlags::ALL,
966            draw_list,
967        }
968    }
969
970    /// Set uv_min (default `[0.0, 0.0]`)
971    pub fn uv_min(mut self, uv_min: [f32; 2]) -> Self {
972        self.uv_min = uv_min;
973        self
974    }
975    /// Set uv_max (default `[1.0, 1.0]`)
976    pub fn uv_max(mut self, uv_max: [f32; 2]) -> Self {
977        self.uv_max = uv_max;
978        self
979    }
980
981    /// Set color tint (default: no tint/white `[1.0, 1.0, 1.0, 1.0]`)
982    pub fn col<C>(mut self, col: C) -> Self
983    where
984        C: Into<ImColor32>,
985    {
986        self.col = col.into();
987        self
988    }
989
990    /// Set flag to indicate rounding on all all corners.
991    pub fn round_all(mut self, value: bool) -> Self {
992        self.draw_flags.set(ImDrawCornerFlags::ALL, value);
993        self
994    }
995
996    /// Set flag to indicate if image's top-left corner will be rounded.
997    pub fn round_top_left(mut self, value: bool) -> Self {
998        self.draw_flags
999            .set(ImDrawCornerFlags::TOP_LEFT, value);
1000        self
1001    }
1002
1003    /// Set flag to indicate if image's top-right corner will be rounded.
1004    pub fn round_top_right(mut self, value: bool) -> Self {
1005        self.draw_flags
1006            .set(ImDrawCornerFlags::TOP_RIGHT, value);
1007        self
1008    }
1009
1010    /// Set flag to indicate if image's bottom-left corner will be rounded.
1011    pub fn round_bot_left(mut self, value: bool) -> Self {
1012        self.draw_flags
1013            .set(ImDrawCornerFlags::BOT_LEFT, value);
1014        self
1015    }
1016
1017    /// Set flag to indicate if image's bottom-right corner will be rounded.
1018    pub fn round_bot_right(mut self, value: bool) -> Self {
1019        self.draw_flags
1020            .set(ImDrawCornerFlags::BOT_RIGHT, value);
1021        self
1022    }
1023
1024    /// Draw the image on the window.
1025    pub fn build(self) {
1026        use std::os::raw::c_void;
1027
1028        unsafe {
1029            sys::ImDrawList_AddImageRounded(
1030                self.draw_list.draw_list,
1031                self.texture_id.id() as *mut c_void,
1032                self.p_min.into(),
1033                self.p_max.into(),
1034                self.uv_min.into(),
1035                self.uv_max.into(),
1036                self.col.into(),
1037                self.rounding,
1038                self.draw_flags.bits() as i32,
1039            );
1040        }
1041    }
1042}