1#![allow(
20 clippy::cast_possible_truncation,
21 clippy::cast_sign_loss,
22 clippy::as_conversions,
23 clippy::unnecessary_cast
24)]
25use crate::texture::TextureId;
26use bitflags::bitflags;
27use std::marker::PhantomData;
28
29use crate::colors::Color;
30use crate::sys;
31
32#[repr(transparent)]
36#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
37pub struct ImColor32(u32);
38
39impl ImColor32 {
40 pub const BLACK: Self = Self(0xff_00_00_00);
42 pub const WHITE: Self = Self(0xff_ff_ff_ff);
44 pub const TRANSPARENT: Self = Self(0);
46
47 #[inline]
49 pub const fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
50 Self(((a as u32) << 24) | (r as u32) | ((g as u32) << 8) | ((b as u32) << 16))
51 }
52
53 #[inline]
55 pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
56 Self::from_rgba(r, g, b, 0xff)
57 }
58
59 pub fn from_rgba_f32s(r: f32, g: f32, b: f32, a: f32) -> Self {
61 Self::from_rgba(
62 (r.clamp(0.0, 1.0) * 255.0) as u8,
63 (g.clamp(0.0, 1.0) * 255.0) as u8,
64 (b.clamp(0.0, 1.0) * 255.0) as u8,
65 (a.clamp(0.0, 1.0) * 255.0) as u8,
66 )
67 }
68
69 #[inline]
71 pub const fn to_bits(self) -> u32 {
72 self.0
73 }
74}
75
76impl From<Color> for ImColor32 {
77 fn from(color: Color) -> Self {
78 Self::from_rgba_f32s(color.r, color.g, color.b, color.a)
79 }
80}
81
82impl From<[f32; 4]> for ImColor32 {
83 fn from(arr: [f32; 4]) -> Self {
84 Self::from_rgba_f32s(arr[0], arr[1], arr[2], arr[3])
85 }
86}
87
88impl From<(f32, f32, f32, f32)> for ImColor32 {
89 fn from((r, g, b, a): (f32, f32, f32, f32)) -> Self {
90 Self::from_rgba_f32s(r, g, b, a)
91 }
92}
93
94impl From<[f32; 3]> for ImColor32 {
95 fn from(arr: [f32; 3]) -> Self {
96 Self::from_rgba_f32s(arr[0], arr[1], arr[2], 1.0)
97 }
98}
99
100impl From<(f32, f32, f32)> for ImColor32 {
101 fn from((r, g, b): (f32, f32, f32)) -> Self {
102 Self::from_rgba_f32s(r, g, b, 1.0)
103 }
104}
105
106impl From<ImColor32> for u32 {
107 fn from(color: ImColor32) -> Self {
108 color.0
109 }
110}
111
112impl From<u32> for ImColor32 {
113 fn from(color: u32) -> Self {
114 ImColor32(color)
115 }
116}
117
118bitflags! {
120 #[repr(transparent)]
122 pub struct DrawListFlags: i32 {
123 const NONE = sys::ImDrawListFlags_None as i32;
125 const ANTI_ALIASED_LINES = sys::ImDrawListFlags_AntiAliasedLines as i32;
127 const ANTI_ALIASED_LINES_USE_TEX = sys::ImDrawListFlags_AntiAliasedLinesUseTex as i32;
129 const ANTI_ALIASED_FILL = sys::ImDrawListFlags_AntiAliasedFill as i32;
131 const ALLOW_VTX_OFFSET = sys::ImDrawListFlags_AllowVtxOffset as i32;
133 }
134}
135
136bitflags! {
137 #[repr(transparent)]
139 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
140 pub struct PolylineFlags: u32 {
141 const NONE = sys::ImDrawFlags_None as u32;
142 const CLOSED = sys::ImDrawFlags_Closed as u32;
143 }
144}
145
146impl Default for PolylineFlags {
147 fn default() -> Self {
148 Self::NONE
149 }
150}
151
152bitflags! {
153 #[repr(transparent)]
158 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
159 pub struct DrawCornerFlags: u32 {
160 const DEFAULT = sys::ImDrawFlags_None as u32;
161 const TOP_LEFT = sys::ImDrawFlags_RoundCornersTopLeft as u32;
162 const TOP_RIGHT = sys::ImDrawFlags_RoundCornersTopRight as u32;
163 const BOTTOM_LEFT = sys::ImDrawFlags_RoundCornersBottomLeft as u32;
164 const BOTTOM_RIGHT = sys::ImDrawFlags_RoundCornersBottomRight as u32;
165 const TOP = sys::ImDrawFlags_RoundCornersTop as u32;
166 const BOTTOM = sys::ImDrawFlags_RoundCornersBottom as u32;
167 const LEFT = sys::ImDrawFlags_RoundCornersLeft as u32;
168 const RIGHT = sys::ImDrawFlags_RoundCornersRight as u32;
169 const ALL = sys::ImDrawFlags_RoundCornersAll as u32;
170 const NO_ROUNDING = sys::ImDrawFlags_RoundCornersNone as u32;
171 }
172}
173
174impl Default for DrawCornerFlags {
175 fn default() -> Self {
176 Self::DEFAULT
177 }
178}
179
180#[repr(transparent)]
185pub struct DrawList(*mut sys::ImDrawList);
186
187impl DrawList {
188 unsafe fn cmd_buffer(&self) -> &[sys::ImDrawCmd] {
190 unsafe {
191 if (*self.0).CmdBuffer.Size <= 0 || (*self.0).CmdBuffer.Data.is_null() {
192 return &[];
193 }
194 let len = match usize::try_from((*self.0).CmdBuffer.Size) {
195 Ok(len) => len,
196 Err(_) => return &[],
197 };
198 std::slice::from_raw_parts((*self.0).CmdBuffer.Data as *const sys::ImDrawCmd, len)
199 }
200 }
201
202 pub fn vtx_buffer(&self) -> &[crate::render::DrawVert] {
204 unsafe {
205 if (*self.0).VtxBuffer.Size <= 0 || (*self.0).VtxBuffer.Data.is_null() {
206 return &[];
207 }
208 let len = match usize::try_from((*self.0).VtxBuffer.Size) {
209 Ok(len) => len,
210 Err(_) => return &[],
211 };
212 std::slice::from_raw_parts(
213 (*self.0).VtxBuffer.Data as *const crate::render::DrawVert,
214 len,
215 )
216 }
217 }
218
219 pub fn idx_buffer(&self) -> &[crate::render::DrawIdx] {
221 unsafe {
222 if (*self.0).IdxBuffer.Size <= 0 || (*self.0).IdxBuffer.Data.is_null() {
223 return &[];
224 }
225 let len = match usize::try_from((*self.0).IdxBuffer.Size) {
226 Ok(len) => len,
227 Err(_) => return &[],
228 };
229 std::slice::from_raw_parts((*self.0).IdxBuffer.Data, len)
230 }
231 }
232
233 pub fn commands(&self) -> DrawCmdIterator<'_> {
235 unsafe {
236 DrawCmdIterator {
237 iter: self.cmd_buffer().iter(),
238 }
239 }
240 }
241}
242
243pub struct OwnedDrawList(*mut sys::ImDrawList);
247
248impl Drop for OwnedDrawList {
249 fn drop(&mut self) {
250 unsafe { sys::ImDrawList_destroy(self.0) }
251 }
252}
253
254impl OwnedDrawList {
255 pub(crate) unsafe fn from_raw(ptr: *mut sys::ImDrawList) -> Self {
259 Self(ptr)
260 }
261
262 pub fn as_view(&self) -> DrawList {
264 DrawList(self.0)
265 }
266
267 pub fn clear_free_memory(&mut self) {
269 unsafe { sys::ImDrawList__ClearFreeMemory(self.0) }
270 }
271
272 pub fn reset_for_new_frame(&mut self) {
274 unsafe { sys::ImDrawList__ResetForNewFrame(self.0) }
275 }
276}
277
278pub struct DrawCmdIterator<'a> {
280 iter: std::slice::Iter<'a, sys::ImDrawCmd>,
281}
282
283impl Iterator for DrawCmdIterator<'_> {
284 type Item = DrawCmd;
285
286 fn next(&mut self) -> Option<Self::Item> {
287 self.iter.next().map(|cmd| {
288 let cmd_params = DrawCmdParams {
289 clip_rect: [
290 cmd.ClipRect.x,
291 cmd.ClipRect.y,
292 cmd.ClipRect.z,
293 cmd.ClipRect.w,
294 ],
295 texture_id: TextureId::from(unsafe {
296 let mut cmd_copy = *cmd;
297 sys::ImDrawCmd_GetTexID(&mut cmd_copy)
298 }),
299 vtx_offset: cmd.VtxOffset as usize,
300 idx_offset: cmd.IdxOffset as usize,
301 };
302
303 match cmd.UserCallback {
304 Some(raw_callback) if raw_callback as usize == usize::MAX => {
305 DrawCmd::ResetRenderState
306 }
307 Some(raw_callback) => DrawCmd::RawCallback {
308 callback: raw_callback,
309 raw_cmd: cmd,
310 },
311 None => DrawCmd::Elements {
312 count: cmd.ElemCount as usize,
313 cmd_params,
314 },
315 }
316 })
317 }
318}
319
320#[derive(Copy, Clone, Debug, PartialEq)]
322pub struct DrawCmdParams {
323 pub clip_rect: [f32; 4],
325 pub texture_id: TextureId,
327 pub vtx_offset: usize,
329 pub idx_offset: usize,
331}
332
333#[derive(Debug, Clone)]
335pub enum DrawCmd {
336 Elements {
338 count: usize,
340 cmd_params: DrawCmdParams,
342 },
343 ResetRenderState,
345 RawCallback {
347 callback: unsafe extern "C" fn(*const sys::ImDrawList, cmd: *const sys::ImDrawCmd),
349 raw_cmd: *const sys::ImDrawCmd,
351 },
352}
353
354enum DrawListType {
355 Window,
356 Background,
357 Foreground,
358}
359
360pub struct DrawListMut<'ui> {
366 draw_list_type: DrawListType,
367 draw_list: *mut sys::ImDrawList,
368 _phantom: PhantomData<&'ui ()>,
369}
370
371static DRAW_LIST_LOADED_WINDOW: std::sync::atomic::AtomicBool =
373 std::sync::atomic::AtomicBool::new(false);
374static DRAW_LIST_LOADED_BACKGROUND: std::sync::atomic::AtomicBool =
375 std::sync::atomic::AtomicBool::new(false);
376static DRAW_LIST_LOADED_FOREGROUND: std::sync::atomic::AtomicBool =
377 std::sync::atomic::AtomicBool::new(false);
378
379impl Drop for DrawListMut<'_> {
380 fn drop(&mut self) {
381 match self.draw_list_type {
382 DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
383 DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
384 DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
385 }
386 .store(false, std::sync::atomic::Ordering::Release);
387 }
388}
389
390impl DrawListMut<'_> {
391 fn lock_draw_list(t: DrawListType) {
392 let lock = match t {
393 DrawListType::Window => &DRAW_LIST_LOADED_WINDOW,
394 DrawListType::Background => &DRAW_LIST_LOADED_BACKGROUND,
395 DrawListType::Foreground => &DRAW_LIST_LOADED_FOREGROUND,
396 };
397
398 if lock
399 .compare_exchange(
400 false,
401 true,
402 std::sync::atomic::Ordering::Acquire,
403 std::sync::atomic::Ordering::Relaxed,
404 )
405 .is_err()
406 {
407 panic!(
408 "A DrawListMut is already in use! You can only have one DrawListMut in use at a time."
409 );
410 }
411 }
412
413 pub(crate) fn window(_ui: &crate::Ui) -> Self {
414 Self::lock_draw_list(DrawListType::Window);
415 Self {
416 draw_list: unsafe { sys::igGetWindowDrawList() },
417 draw_list_type: DrawListType::Window,
418 _phantom: PhantomData,
419 }
420 }
421
422 pub(crate) fn background(_ui: &crate::Ui) -> Self {
423 Self::lock_draw_list(DrawListType::Background);
424 Self {
425 draw_list: unsafe { sys::igGetBackgroundDrawList(std::ptr::null_mut()) },
426 draw_list_type: DrawListType::Background,
427 _phantom: PhantomData,
428 }
429 }
430
431 pub(crate) fn foreground(_ui: &crate::Ui) -> Self {
432 Self::lock_draw_list(DrawListType::Foreground);
433 Self {
434 draw_list: unsafe { sys::igGetForegroundDrawList_ViewportPtr(std::ptr::null_mut()) },
435 draw_list_type: DrawListType::Foreground,
436 _phantom: PhantomData,
437 }
438 }
439}
440
441impl<'ui> DrawListMut<'ui> {
443 #[doc(alias = "ChannelsSplit")]
445 pub fn channels_split<F: FnOnce(&ChannelsSplit<'ui>)>(&'ui self, channels_count: u32, f: F) {
446 unsafe { sys::ImDrawList_ChannelsSplit(self.draw_list, channels_count as i32) };
447 f(&ChannelsSplit {
448 draw_list: self,
449 channels_count,
450 });
451 unsafe { sys::ImDrawList_ChannelsMerge(self.draw_list) };
452 }
453 pub fn add_line<C>(
455 &'ui self,
456 p1: impl Into<sys::ImVec2>,
457 p2: impl Into<sys::ImVec2>,
458 c: C,
459 ) -> Line<'ui>
460 where
461 C: Into<ImColor32>,
462 {
463 Line::new(self, p1, p2, c)
464 }
465
466 pub fn add_rect<C>(
469 &'ui self,
470 p1: impl Into<sys::ImVec2>,
471 p2: impl Into<sys::ImVec2>,
472 c: C,
473 ) -> Rect<'ui>
474 where
475 C: Into<ImColor32>,
476 {
477 Rect::new(self, p1, p2, c)
478 }
479
480 #[doc(alias = "AddRectFilledMultiColor")]
482 pub fn add_rect_filled_multicolor<C1, C2, C3, C4>(
483 &self,
484 p1: impl Into<sys::ImVec2>,
485 p2: impl Into<sys::ImVec2>,
486 col_upr_left: C1,
487 col_upr_right: C2,
488 col_bot_right: C3,
489 col_bot_left: C4,
490 ) where
491 C1: Into<ImColor32>,
492 C2: Into<ImColor32>,
493 C3: Into<ImColor32>,
494 C4: Into<ImColor32>,
495 {
496 let p_min: sys::ImVec2 = p1.into();
497 let p_max: sys::ImVec2 = p2.into();
498 let c_ul: u32 = col_upr_left.into().into();
499 let c_ur: u32 = col_upr_right.into().into();
500 let c_br: u32 = col_bot_right.into().into();
501 let c_bl: u32 = col_bot_left.into().into();
502 unsafe {
503 sys::ImDrawList_AddRectFilledMultiColor(
504 self.draw_list,
505 p_min,
506 p_max,
507 c_ul,
508 c_ur,
509 c_br,
510 c_bl,
511 );
512 }
513 }
514
515 pub fn add_circle<C>(
517 &'ui self,
518 center: impl Into<sys::ImVec2>,
519 radius: f32,
520 color: C,
521 ) -> Circle<'ui>
522 where
523 C: Into<ImColor32>,
524 {
525 Circle::new(self, center, radius, color)
526 }
527
528 #[doc(alias = "AddBezier", alias = "AddBezierCubic")]
531 pub fn add_bezier_curve(
532 &'ui self,
533 pos0: impl Into<sys::ImVec2>,
534 cp0: impl Into<sys::ImVec2>,
535 cp1: impl Into<sys::ImVec2>,
536 pos1: impl Into<sys::ImVec2>,
537 color: impl Into<ImColor32>,
538 ) -> BezierCurve<'ui> {
539 BezierCurve::new(self, pos0, cp0, cp1, pos1, color)
540 }
541
542 #[doc(alias = "AddTriangleFilled", alias = "AddTriangle")]
544 pub fn add_triangle<C>(
545 &'ui self,
546 p1: impl Into<sys::ImVec2>,
547 p2: impl Into<sys::ImVec2>,
548 p3: impl Into<sys::ImVec2>,
549 c: C,
550 ) -> Triangle<'ui>
551 where
552 C: Into<ImColor32>,
553 {
554 Triangle::new(self, p1, p2, p3, c)
555 }
556
557 #[doc(alias = "AddPolyline", alias = "AddConvexPolyFilled")]
561 pub fn add_polyline<C, P>(&'ui self, points: Vec<P>, c: C) -> Polyline<'ui>
562 where
563 C: Into<ImColor32>,
564 P: Into<sys::ImVec2>,
565 {
566 Polyline::new(self, points, c)
567 }
568
569 #[doc(alias = "PathClear")]
573 pub fn path_clear(&self) {
574 unsafe {
575 let draw_list = self.draw_list;
577 (*draw_list)._Path.Size = 0;
578 }
579 }
580
581 #[doc(alias = "PathLineTo")]
583 pub fn path_line_to(&self, pos: impl Into<sys::ImVec2>) {
584 unsafe { sys::ImDrawList_PathLineTo(self.draw_list, pos.into()) }
585 }
586
587 #[doc(alias = "PathLineToMergeDuplicate")]
589 pub fn path_line_to_merge_duplicate(&self, pos: impl Into<sys::ImVec2>) {
590 unsafe { sys::ImDrawList_PathLineToMergeDuplicate(self.draw_list, pos.into()) }
591 }
592
593 #[doc(alias = "PathArcTo")]
595 pub fn path_arc_to(
596 &self,
597 center: impl Into<sys::ImVec2>,
598 radius: f32,
599 a_min: f32,
600 a_max: f32,
601 num_segments: i32,
602 ) {
603 unsafe {
604 let center_vec: sys::ImVec2 = center.into();
605 sys::ImDrawList_PathArcTo(
606 self.draw_list,
607 center_vec,
608 radius,
609 a_min,
610 a_max,
611 num_segments,
612 );
613 }
614 }
615
616 #[doc(alias = "PathArcToFast")]
618 pub fn path_arc_to_fast(
619 &self,
620 center: impl Into<sys::ImVec2>,
621 radius: f32,
622 a_min_of_12: i32,
623 a_max_of_12: i32,
624 ) {
625 unsafe {
626 let center_vec: sys::ImVec2 = center.into();
627 sys::ImDrawList_PathArcToFast(
628 self.draw_list,
629 center_vec,
630 radius,
631 a_min_of_12,
632 a_max_of_12,
633 );
634 }
635 }
636
637 #[doc(alias = "PathRect")]
639 pub fn path_rect(
640 &self,
641 rect_min: impl Into<sys::ImVec2>,
642 rect_max: impl Into<sys::ImVec2>,
643 rounding: f32,
644 flags: DrawCornerFlags,
645 ) {
646 unsafe {
647 let min_vec: sys::ImVec2 = rect_min.into();
648 let max_vec: sys::ImVec2 = rect_max.into();
649 sys::ImDrawList_PathRect(
650 self.draw_list,
651 min_vec,
652 max_vec,
653 rounding,
654 flags.bits() as sys::ImDrawFlags,
655 );
656 }
657 }
658
659 #[doc(alias = "PathEllipticalArcTo")]
661 pub fn path_elliptical_arc_to(
662 &self,
663 center: impl Into<sys::ImVec2>,
664 radius: impl Into<sys::ImVec2>,
665 rot: f32,
666 a_min: f32,
667 a_max: f32,
668 num_segments: i32,
669 ) {
670 unsafe {
671 sys::ImDrawList_PathEllipticalArcTo(
672 self.draw_list,
673 center.into(),
674 radius.into(),
675 rot,
676 a_min,
677 a_max,
678 num_segments,
679 )
680 }
681 }
682
683 #[doc(alias = "PathBezierQuadraticCurveTo")]
685 pub fn path_bezier_quadratic_curve_to(
686 &self,
687 p2: impl Into<sys::ImVec2>,
688 p3: impl Into<sys::ImVec2>,
689 num_segments: i32,
690 ) {
691 unsafe {
692 sys::ImDrawList_PathBezierQuadraticCurveTo(
693 self.draw_list,
694 p2.into(),
695 p3.into(),
696 num_segments,
697 )
698 }
699 }
700
701 #[doc(alias = "PathBezierCubicCurveTo")]
703 pub fn path_bezier_cubic_curve_to(
704 &self,
705 p2: impl Into<sys::ImVec2>,
706 p3: impl Into<sys::ImVec2>,
707 p4: impl Into<sys::ImVec2>,
708 num_segments: i32,
709 ) {
710 unsafe {
711 sys::ImDrawList_PathBezierCubicCurveTo(
712 self.draw_list,
713 p2.into(),
714 p3.into(),
715 p4.into(),
716 num_segments,
717 )
718 }
719 }
720
721 #[doc(alias = "PathStroke")]
723 pub fn path_stroke(&self, color: impl Into<ImColor32>, flags: PolylineFlags, thickness: f32) {
724 unsafe {
725 let draw_list = self.draw_list;
727 let path = &mut (*draw_list)._Path;
728
729 if path.Size > 0 {
730 sys::ImDrawList_AddPolyline(
731 self.draw_list,
732 path.Data,
733 path.Size,
734 color.into().into(),
735 flags.bits() as sys::ImDrawFlags,
736 thickness,
737 );
738 path.Size = 0; }
740 }
741 }
742
743 #[doc(alias = "PathFillConvex")]
745 pub fn path_fill_convex(&self, color: impl Into<ImColor32>) {
746 unsafe {
747 let draw_list = self.draw_list;
749 let path = &mut (*draw_list)._Path;
750
751 if path.Size > 0 {
752 sys::ImDrawList_AddConvexPolyFilled(
753 self.draw_list,
754 path.Data,
755 path.Size,
756 color.into().into(),
757 );
758 path.Size = 0; }
760 }
761 }
762
763 pub fn add_text(
765 &self,
766 pos: impl Into<sys::ImVec2>,
767 col: impl Into<ImColor32>,
768 text: impl AsRef<str>,
769 ) {
770 use std::os::raw::c_char;
771
772 let text = text.as_ref();
773 let pos: sys::ImVec2 = pos.into();
774 let col = col.into();
775
776 unsafe {
777 let start = text.as_ptr() as *const c_char;
778 let end = (start as usize + text.len()) as *const c_char;
779 sys::ImDrawList_AddText_Vec2(self.draw_list, pos, col.into(), start, end);
780 }
781 }
782
783 #[doc(alias = "AddText")]
787 pub fn add_text_with_font(
788 &self,
789 font: &crate::fonts::Font,
790 font_size: f32,
791 pos: impl Into<sys::ImVec2>,
792 col: impl Into<ImColor32>,
793 text: impl AsRef<str>,
794 wrap_width: f32,
795 cpu_fine_clip_rect: Option<[f32; 4]>,
796 ) {
797 use std::os::raw::c_char;
798 let text = text.as_ref();
799 let pos: sys::ImVec2 = pos.into();
800 let col = col.into();
801 let font_ptr = font.raw();
802
803 let clip_vec4 = cpu_fine_clip_rect.map(|r| sys::ImVec4 {
804 x: r[0],
805 y: r[1],
806 z: r[2],
807 w: r[3],
808 });
809 let clip_ptr = match clip_vec4.as_ref() {
810 Some(v) => v as *const sys::ImVec4,
811 None => std::ptr::null(),
812 };
813
814 unsafe {
815 let start = text.as_ptr() as *const c_char;
816 let end = (start as usize + text.len()) as *const c_char;
817 sys::ImDrawList_AddText_FontPtr(
818 self.draw_list,
819 font_ptr,
820 font_size,
821 pos,
822 col.into(),
823 start,
824 end,
825 wrap_width,
826 clip_ptr,
827 );
828 }
829 }
830
831 #[doc(alias = "PushTexture")]
849 pub fn push_texture(&self, texture: impl Into<crate::texture::TextureRef>) {
850 let tex_ref = texture.into().raw();
851 unsafe { sys::ImDrawList_PushTexture(self.draw_list, tex_ref) }
852 }
853
854 #[doc(alias = "PopTexture")]
856 pub fn pop_texture(&self) {
857 unsafe {
858 sys::ImDrawList_PopTexture(self.draw_list);
859 }
860 }
861
862 #[doc(alias = "PushClipRect")]
864 pub fn push_clip_rect(
865 &self,
866 clip_rect_min: impl Into<sys::ImVec2>,
867 clip_rect_max: impl Into<sys::ImVec2>,
868 intersect_with_current: bool,
869 ) {
870 unsafe {
871 sys::ImDrawList_PushClipRect(
872 self.draw_list,
873 clip_rect_min.into(),
874 clip_rect_max.into(),
875 intersect_with_current,
876 )
877 }
878 }
879
880 #[doc(alias = "PushClipRectFullScreen")]
882 pub fn push_clip_rect_full_screen(&self) {
883 unsafe { sys::ImDrawList_PushClipRectFullScreen(self.draw_list) }
884 }
885
886 #[doc(alias = "PopClipRect")]
888 pub fn pop_clip_rect(&self) {
889 unsafe { sys::ImDrawList_PopClipRect(self.draw_list) }
890 }
891
892 pub fn clip_rect_min(&self) -> [f32; 2] {
894 let out = unsafe { sys::ImDrawList_GetClipRectMin(self.draw_list) };
895 out.into()
896 }
897
898 pub fn clip_rect_max(&self) -> [f32; 2] {
900 let out = unsafe { sys::ImDrawList_GetClipRectMax(self.draw_list) };
901 out.into()
902 }
903
904 pub fn with_clip_rect<F>(
906 &self,
907 clip_rect_min: impl Into<sys::ImVec2>,
908 clip_rect_max: impl Into<sys::ImVec2>,
909 f: F,
910 ) where
911 F: FnOnce(),
912 {
913 self.push_clip_rect(clip_rect_min, clip_rect_max, false);
914 f();
915 self.pop_clip_rect();
916 }
917
918 #[doc(alias = "AddImage")]
920 pub fn add_image(
921 &self,
922 texture: impl Into<crate::texture::TextureRef>,
923 p_min: impl Into<sys::ImVec2>,
924 p_max: impl Into<sys::ImVec2>,
925 uv_min: impl Into<sys::ImVec2>,
926 uv_max: impl Into<sys::ImVec2>,
927 col: impl Into<ImColor32>,
928 ) {
929 let p_min: sys::ImVec2 = p_min.into();
933 let p_max: sys::ImVec2 = p_max.into();
934 let uv_min: sys::ImVec2 = uv_min.into();
935 let uv_max: sys::ImVec2 = uv_max.into();
936 let col = col.into().to_bits();
937 let tex_ref = texture.into().raw();
938 unsafe {
939 sys::ImDrawList_AddImage(self.draw_list, tex_ref, p_min, p_max, uv_min, uv_max, col)
940 }
941 }
942
943 #[doc(alias = "AddImageQuad")]
945 pub fn add_image_quad(
946 &self,
947 texture: impl Into<crate::texture::TextureRef>,
948 p1: impl Into<sys::ImVec2>,
949 p2: impl Into<sys::ImVec2>,
950 p3: impl Into<sys::ImVec2>,
951 p4: impl Into<sys::ImVec2>,
952 uv1: impl Into<sys::ImVec2>,
953 uv2: impl Into<sys::ImVec2>,
954 uv3: impl Into<sys::ImVec2>,
955 uv4: impl Into<sys::ImVec2>,
956 col: impl Into<ImColor32>,
957 ) {
958 let p1: sys::ImVec2 = p1.into();
967 let p2: sys::ImVec2 = p2.into();
968 let p3: sys::ImVec2 = p3.into();
969 let p4: sys::ImVec2 = p4.into();
970 let uv1: sys::ImVec2 = uv1.into();
971 let uv2: sys::ImVec2 = uv2.into();
972 let uv3: sys::ImVec2 = uv3.into();
973 let uv4: sys::ImVec2 = uv4.into();
974 let col = col.into().to_bits();
975 let tex_ref = texture.into().raw();
976 unsafe {
977 sys::ImDrawList_AddImageQuad(
978 self.draw_list,
979 tex_ref,
980 p1,
981 p2,
982 p3,
983 p4,
984 uv1,
985 uv2,
986 uv3,
987 uv4,
988 col,
989 )
990 }
991 }
992
993 #[doc(alias = "AddImageRounded")]
995 pub fn add_image_rounded(
996 &self,
997 texture: impl Into<crate::texture::TextureRef>,
998 p_min: impl Into<sys::ImVec2>,
999 p_max: impl Into<sys::ImVec2>,
1000 uv_min: impl Into<sys::ImVec2>,
1001 uv_max: impl Into<sys::ImVec2>,
1002 col: impl Into<ImColor32>,
1003 rounding: f32,
1004 flags: DrawCornerFlags,
1005 ) {
1006 let p_min: sys::ImVec2 = p_min.into();
1017 let p_max: sys::ImVec2 = p_max.into();
1018 let uv_min: sys::ImVec2 = uv_min.into();
1019 let uv_max: sys::ImVec2 = uv_max.into();
1020 let col = col.into().to_bits();
1021 let tex_ref = texture.into().raw();
1022 unsafe {
1023 sys::ImDrawList_AddImageRounded(
1024 self.draw_list,
1025 tex_ref,
1026 p_min,
1027 p_max,
1028 uv_min,
1029 uv_max,
1030 col,
1031 rounding,
1032 flags.bits() as sys::ImDrawFlags,
1033 )
1034 }
1035 }
1036
1037 #[doc(alias = "AddQuad")]
1039 pub fn add_quad<C>(
1040 &self,
1041 p1: impl Into<sys::ImVec2>,
1042 p2: impl Into<sys::ImVec2>,
1043 p3: impl Into<sys::ImVec2>,
1044 p4: impl Into<sys::ImVec2>,
1045 col: C,
1046 thickness: f32,
1047 ) where
1048 C: Into<ImColor32>,
1049 {
1050 unsafe {
1051 sys::ImDrawList_AddQuad(
1052 self.draw_list,
1053 p1.into(),
1054 p2.into(),
1055 p3.into(),
1056 p4.into(),
1057 col.into().into(),
1058 thickness,
1059 )
1060 }
1061 }
1062
1063 #[doc(alias = "AddQuadFilled")]
1065 pub fn add_quad_filled<C>(
1066 &self,
1067 p1: impl Into<sys::ImVec2>,
1068 p2: impl Into<sys::ImVec2>,
1069 p3: impl Into<sys::ImVec2>,
1070 p4: impl Into<sys::ImVec2>,
1071 col: C,
1072 ) where
1073 C: Into<ImColor32>,
1074 {
1075 unsafe {
1076 sys::ImDrawList_AddQuadFilled(
1077 self.draw_list,
1078 p1.into(),
1079 p2.into(),
1080 p3.into(),
1081 p4.into(),
1082 col.into().into(),
1083 )
1084 }
1085 }
1086
1087 #[doc(alias = "AddNgon")]
1089 pub fn add_ngon<C>(
1090 &self,
1091 center: impl Into<sys::ImVec2>,
1092 radius: f32,
1093 col: C,
1094 num_segments: i32,
1095 thickness: f32,
1096 ) where
1097 C: Into<ImColor32>,
1098 {
1099 unsafe {
1100 sys::ImDrawList_AddNgon(
1101 self.draw_list,
1102 center.into(),
1103 radius,
1104 col.into().into(),
1105 num_segments,
1106 thickness,
1107 )
1108 }
1109 }
1110
1111 #[doc(alias = "AddNgonFilled")]
1113 pub fn add_ngon_filled<C>(
1114 &self,
1115 center: impl Into<sys::ImVec2>,
1116 radius: f32,
1117 col: C,
1118 num_segments: i32,
1119 ) where
1120 C: Into<ImColor32>,
1121 {
1122 unsafe {
1123 sys::ImDrawList_AddNgonFilled(
1124 self.draw_list,
1125 center.into(),
1126 radius,
1127 col.into().into(),
1128 num_segments,
1129 )
1130 }
1131 }
1132
1133 #[doc(alias = "AddEllipse")]
1135 pub fn add_ellipse<C>(
1136 &self,
1137 center: impl Into<sys::ImVec2>,
1138 radius: impl Into<sys::ImVec2>,
1139 col: C,
1140 rot: f32,
1141 num_segments: i32,
1142 thickness: f32,
1143 ) where
1144 C: Into<ImColor32>,
1145 {
1146 unsafe {
1147 sys::ImDrawList_AddEllipse(
1148 self.draw_list,
1149 center.into(),
1150 radius.into(),
1151 col.into().into(),
1152 rot,
1153 num_segments,
1154 thickness,
1155 )
1156 }
1157 }
1158
1159 #[doc(alias = "AddEllipseFilled")]
1161 pub fn add_ellipse_filled<C>(
1162 &self,
1163 center: impl Into<sys::ImVec2>,
1164 radius: impl Into<sys::ImVec2>,
1165 col: C,
1166 rot: f32,
1167 num_segments: i32,
1168 ) where
1169 C: Into<ImColor32>,
1170 {
1171 unsafe {
1172 sys::ImDrawList_AddEllipseFilled(
1173 self.draw_list,
1174 center.into(),
1175 radius.into(),
1176 col.into().into(),
1177 rot,
1178 num_segments,
1179 )
1180 }
1181 }
1182
1183 #[doc(alias = "AddBezierQuadratic")]
1185 pub fn add_bezier_quadratic<C>(
1186 &self,
1187 p1: impl Into<sys::ImVec2>,
1188 p2: impl Into<sys::ImVec2>,
1189 p3: impl Into<sys::ImVec2>,
1190 col: C,
1191 thickness: f32,
1192 num_segments: i32,
1193 ) where
1194 C: Into<ImColor32>,
1195 {
1196 unsafe {
1197 sys::ImDrawList_AddBezierQuadratic(
1198 self.draw_list,
1199 p1.into(),
1200 p2.into(),
1201 p3.into(),
1202 col.into().into(),
1203 thickness,
1204 num_segments,
1205 )
1206 }
1207 }
1208
1209 #[doc(alias = "AddConcavePolyFilled")]
1211 pub fn add_concave_poly_filled<C, P>(&self, points: &[P], col: C)
1212 where
1213 C: Into<ImColor32>,
1214 P: Copy + Into<sys::ImVec2>,
1215 {
1216 let mut buf: Vec<sys::ImVec2> = Vec::with_capacity(points.len());
1217 for p in points.iter().copied() {
1218 buf.push(p.into());
1219 }
1220 let count = match i32::try_from(buf.len()) {
1221 Ok(n) => n,
1222 Err(_) => return,
1223 };
1224 unsafe {
1225 sys::ImDrawList_AddConcavePolyFilled(
1226 self.draw_list,
1227 buf.as_ptr(),
1228 count,
1229 col.into().into(),
1230 )
1231 }
1232 }
1233
1234 #[doc(alias = "PathFillConcave")]
1236 pub fn path_fill_concave(&self, color: impl Into<ImColor32>) {
1237 unsafe { sys::ImDrawList_PathFillConcave(self.draw_list, color.into().into()) }
1238 }
1239
1240 #[doc(alias = "AddCallback")]
1251 pub unsafe fn add_callback(
1252 &self,
1253 callback: sys::ImDrawCallback,
1254 userdata: *mut std::os::raw::c_void,
1255 userdata_size: usize,
1256 ) {
1257 unsafe { sys::ImDrawList_AddCallback(self.draw_list, callback, userdata, userdata_size) }
1258 }
1259
1260 #[doc(alias = "AddDrawCmd")]
1262 pub fn add_draw_cmd(&self) {
1263 unsafe { sys::ImDrawList_AddDrawCmd(self.draw_list) }
1264 }
1265
1266 #[doc(alias = "CloneOutput")]
1270 pub fn clone_output(&self) -> OwnedDrawList {
1271 unsafe { OwnedDrawList::from_raw(sys::ImDrawList_CloneOutput(self.draw_list)) }
1272 }
1273}
1274
1275pub struct ChannelsSplit<'ui> {
1277 draw_list: &'ui DrawListMut<'ui>,
1278 channels_count: u32,
1279}
1280
1281impl ChannelsSplit<'_> {
1282 #[doc(alias = "ChannelsSetCurrent")]
1284 pub fn set_current(&self, channel_index: u32) {
1285 assert!(
1286 channel_index < self.channels_count,
1287 "Channel index {} out of range {}",
1288 channel_index,
1289 self.channels_count
1290 );
1291 unsafe {
1292 sys::ImDrawList_ChannelsSetCurrent(self.draw_list.draw_list, channel_index as i32)
1293 };
1294 }
1295}
1296
1297#[must_use = "call .build() to register the callback"]
1299pub struct Callback<'ui, F> {
1300 draw_list: &'ui DrawListMut<'ui>,
1301 callback: F,
1302}
1303
1304impl<'ui, F: FnOnce() + 'static> Callback<'ui, F> {
1305 pub fn new(draw_list: &'ui DrawListMut<'_>, callback: F) -> Self {
1307 Self {
1308 draw_list,
1309 callback,
1310 }
1311 }
1312
1313 pub fn build(self) {
1315 use std::os::raw::c_void;
1316 let ptr: *mut F = Box::into_raw(Box::new(self.callback));
1322 unsafe {
1323 sys::ImDrawList_AddCallback(
1324 self.draw_list.draw_list,
1325 Some(Self::run_callback),
1326 ptr as *mut c_void,
1327 0,
1328 );
1329 }
1330 }
1331
1332 unsafe extern "C" fn run_callback(
1333 _parent_list: *const sys::ImDrawList,
1334 cmd: *const sys::ImDrawCmd,
1335 ) {
1336 if cmd.is_null() {
1337 return;
1338 }
1339 let cmd_ptr = cmd as *mut sys::ImDrawCmd;
1340 if unsafe { (*cmd_ptr).UserCallbackData.is_null() } {
1341 return;
1342 }
1343 if unsafe { (*cmd_ptr).UserCallbackDataOffset } != -1 {
1344 eprintln!("dear-imgui-rs: unexpected UserCallbackDataOffset (expected -1)");
1345 std::process::abort();
1346 }
1347 if unsafe { (*cmd_ptr).UserCallbackDataSize } != 0 {
1348 eprintln!("dear-imgui-rs: unexpected UserCallbackDataSize (expected 0)");
1349 std::process::abort();
1350 }
1351 let data_ptr = unsafe { (*cmd_ptr).UserCallbackData as *mut F };
1353 if data_ptr.is_null() {
1354 return;
1355 }
1356 unsafe {
1358 (*cmd_ptr).UserCallbackData = std::ptr::null_mut();
1359 (*cmd_ptr).UserCallbackDataSize = 0;
1360 (*cmd_ptr).UserCallbackDataOffset = 0;
1361 }
1362 let cb = unsafe { Box::from_raw(data_ptr) };
1363 let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || {
1364 cb();
1365 }));
1366 if res.is_err() {
1367 eprintln!("dear-imgui-rs: panic in DrawList callback");
1368 std::process::abort();
1369 }
1370 }
1371}
1372
1373#[cfg(test)]
1374mod callback_tests {
1375 use super::*;
1376
1377 #[test]
1378 fn safe_draw_callback_uses_direct_user_data_pointer() {
1379 fn noop() {}
1380
1381 let shared = unsafe { sys::ImDrawListSharedData_ImDrawListSharedData() };
1382 assert!(!shared.is_null());
1383 let raw_draw_list = unsafe { sys::ImDrawList_ImDrawList(shared) };
1384 assert!(!raw_draw_list.is_null());
1385
1386 unsafe { sys::ImDrawList_AddDrawCmd(raw_draw_list) };
1388
1389 let draw_list = DrawListMut {
1390 draw_list_type: DrawListType::Window,
1391 draw_list: raw_draw_list,
1392 _phantom: PhantomData,
1393 };
1394 draw_list.add_callback_safe(noop).build();
1395
1396 let cmd_buffer = unsafe { &(*draw_list.draw_list).CmdBuffer };
1397 assert!(cmd_buffer.Size > 0);
1398 assert!(!cmd_buffer.Data.is_null());
1399
1400 let (cmd_ptr, cmd_copy) = {
1401 let cmds = unsafe {
1402 let len = usize::try_from(cmd_buffer.Size)
1403 .expect("expected non-negative CmdBuffer.Size in test");
1404 std::slice::from_raw_parts(cmd_buffer.Data, len)
1405 };
1406 let (i, cmd) = cmds
1407 .iter()
1408 .enumerate()
1409 .find(|(_, cmd)| cmd.UserCallback.is_some() && !cmd.UserCallbackData.is_null())
1410 .expect("expected callback command to be present");
1411
1412 let cmd_ptr = unsafe { cmd_buffer.Data.add(i) as *const sys::ImDrawCmd };
1413 (cmd_ptr, *cmd)
1414 };
1415
1416 assert!(cmd_copy.UserCallback.is_some());
1417 assert_eq!(cmd_copy.UserCallbackDataOffset, -1);
1418 assert_eq!(cmd_copy.UserCallbackDataSize, 0);
1419 assert!(!cmd_copy.UserCallbackData.is_null());
1420
1421 unsafe { cmd_copy.UserCallback.unwrap()(draw_list.draw_list as *const _, cmd_ptr) }
1423
1424 let cmd_after = unsafe { *cmd_ptr };
1425 assert!(cmd_after.UserCallbackData.is_null());
1426
1427 unsafe {
1428 sys::ImDrawList_destroy(raw_draw_list);
1429 sys::ImDrawListSharedData_destroy(shared);
1430 }
1431 }
1432}
1433
1434impl<'ui> DrawListMut<'ui> {
1435 #[cfg(not(target_arch = "wasm32"))]
1438 pub fn add_callback_safe<F: FnOnce() + 'static>(&'ui self, callback: F) -> Callback<'ui, F> {
1439 Callback::new(self, callback)
1440 }
1441
1442 #[cfg(target_arch = "wasm32")]
1449 pub fn add_callback_safe<F: FnOnce() + 'static>(&'ui self, _callback: F) -> Callback<'ui, F> {
1450 panic!(
1451 "DrawListMut::add_callback_safe is not supported on wasm32 targets; \
1452 C->Rust callbacks are not available in the import-style web build."
1453 );
1454 }
1455}
1456
1457impl<'ui> DrawListMut<'ui> {
1458 pub unsafe fn prim_reserve(&self, idx_count: i32, vtx_count: i32) {
1463 unsafe { sys::ImDrawList_PrimReserve(self.draw_list, idx_count, vtx_count) }
1464 }
1465
1466 pub unsafe fn prim_unreserve(&self, idx_count: i32, vtx_count: i32) {
1471 unsafe { sys::ImDrawList_PrimUnreserve(self.draw_list, idx_count, vtx_count) }
1472 }
1473
1474 pub unsafe fn prim_rect(
1479 &self,
1480 a: impl Into<sys::ImVec2>,
1481 b: impl Into<sys::ImVec2>,
1482 col: impl Into<ImColor32>,
1483 ) {
1484 unsafe { sys::ImDrawList_PrimRect(self.draw_list, a.into(), b.into(), col.into().into()) }
1485 }
1486
1487 pub unsafe fn prim_rect_uv(
1492 &self,
1493 a: impl Into<sys::ImVec2>,
1494 b: impl Into<sys::ImVec2>,
1495 uv_a: impl Into<sys::ImVec2>,
1496 uv_b: impl Into<sys::ImVec2>,
1497 col: impl Into<ImColor32>,
1498 ) {
1499 unsafe {
1500 sys::ImDrawList_PrimRectUV(
1501 self.draw_list,
1502 a.into(),
1503 b.into(),
1504 uv_a.into(),
1505 uv_b.into(),
1506 col.into().into(),
1507 )
1508 }
1509 }
1510
1511 pub unsafe fn prim_quad_uv(
1516 &self,
1517 a: impl Into<sys::ImVec2>,
1518 b: impl Into<sys::ImVec2>,
1519 c: impl Into<sys::ImVec2>,
1520 d: impl Into<sys::ImVec2>,
1521 uv_a: impl Into<sys::ImVec2>,
1522 uv_b: impl Into<sys::ImVec2>,
1523 uv_c: impl Into<sys::ImVec2>,
1524 uv_d: impl Into<sys::ImVec2>,
1525 col: impl Into<ImColor32>,
1526 ) {
1527 unsafe {
1528 sys::ImDrawList_PrimQuadUV(
1529 self.draw_list,
1530 a.into(),
1531 b.into(),
1532 c.into(),
1533 d.into(),
1534 uv_a.into(),
1535 uv_b.into(),
1536 uv_c.into(),
1537 uv_d.into(),
1538 col.into().into(),
1539 )
1540 }
1541 }
1542
1543 pub unsafe fn prim_write_vtx(
1548 &self,
1549 pos: impl Into<sys::ImVec2>,
1550 uv: impl Into<sys::ImVec2>,
1551 col: impl Into<ImColor32>,
1552 ) {
1553 unsafe {
1554 sys::ImDrawList_PrimWriteVtx(self.draw_list, pos.into(), uv.into(), col.into().into())
1555 }
1556 }
1557
1558 pub unsafe fn prim_write_idx(&self, idx: sys::ImDrawIdx) {
1563 unsafe { sys::ImDrawList_PrimWriteIdx(self.draw_list, idx) }
1564 }
1565
1566 pub unsafe fn prim_vtx(
1571 &self,
1572 pos: impl Into<sys::ImVec2>,
1573 uv: impl Into<sys::ImVec2>,
1574 col: impl Into<ImColor32>,
1575 ) {
1576 unsafe { sys::ImDrawList_PrimVtx(self.draw_list, pos.into(), uv.into(), col.into().into()) }
1577 }
1578}
1579
1580#[must_use = "should call .build() to draw the object"]
1582pub struct Line<'ui> {
1583 p1: [f32; 2],
1584 p2: [f32; 2],
1585 color: ImColor32,
1586 thickness: f32,
1587 draw_list: &'ui DrawListMut<'ui>,
1588}
1589
1590impl<'ui> Line<'ui> {
1591 fn new<C>(
1592 draw_list: &'ui DrawListMut<'_>,
1593 p1: impl Into<sys::ImVec2>,
1594 p2: impl Into<sys::ImVec2>,
1595 c: C,
1596 ) -> Self
1597 where
1598 C: Into<ImColor32>,
1599 {
1600 Self {
1601 p1: {
1602 let v: sys::ImVec2 = p1.into();
1603 v.into()
1604 },
1605 p2: {
1606 let v: sys::ImVec2 = p2.into();
1607 v.into()
1608 },
1609 color: c.into(),
1610 thickness: 1.0,
1611 draw_list,
1612 }
1613 }
1614
1615 pub fn thickness(mut self, thickness: f32) -> Self {
1617 self.thickness = thickness;
1618 self
1619 }
1620
1621 pub fn build(self) {
1623 unsafe {
1624 let p1 = sys::ImVec2 {
1625 x: self.p1[0],
1626 y: self.p1[1],
1627 };
1628 let p2 = sys::ImVec2 {
1629 x: self.p2[0],
1630 y: self.p2[1],
1631 };
1632 sys::ImDrawList_AddLine(
1633 self.draw_list.draw_list,
1634 p1,
1635 p2,
1636 self.color.into(),
1637 self.thickness,
1638 )
1639 }
1640 }
1641}
1642
1643#[must_use = "should call .build() to draw the object"]
1645pub struct Rect<'ui> {
1646 p1: [f32; 2],
1647 p2: [f32; 2],
1648 color: ImColor32,
1649 rounding: f32,
1650 flags: DrawCornerFlags,
1651 thickness: f32,
1652 filled: bool,
1653 draw_list: &'ui DrawListMut<'ui>,
1654}
1655
1656impl<'ui> Rect<'ui> {
1657 fn new<C>(
1658 draw_list: &'ui DrawListMut<'_>,
1659 p1: impl Into<sys::ImVec2>,
1660 p2: impl Into<sys::ImVec2>,
1661 c: C,
1662 ) -> Self
1663 where
1664 C: Into<ImColor32>,
1665 {
1666 Self {
1667 p1: {
1668 let v: sys::ImVec2 = p1.into();
1669 v.into()
1670 },
1671 p2: {
1672 let v: sys::ImVec2 = p2.into();
1673 v.into()
1674 },
1675 color: c.into(),
1676 rounding: 0.0,
1677 flags: DrawCornerFlags::ALL,
1678 thickness: 1.0,
1679 filled: false,
1680 draw_list,
1681 }
1682 }
1683
1684 pub fn rounding(mut self, rounding: f32) -> Self {
1686 self.rounding = rounding;
1687 self
1688 }
1689
1690 pub fn thickness(mut self, thickness: f32) -> Self {
1692 self.thickness = thickness;
1693 self
1694 }
1695
1696 pub fn filled(mut self, filled: bool) -> Self {
1698 self.filled = filled;
1699 self
1700 }
1701
1702 pub fn flags(mut self, flags: DrawCornerFlags) -> Self {
1704 self.flags = flags;
1705 self
1706 }
1707
1708 pub fn build(self) {
1710 let p1 = sys::ImVec2 {
1711 x: self.p1[0],
1712 y: self.p1[1],
1713 };
1714 let p2 = sys::ImVec2 {
1715 x: self.p2[0],
1716 y: self.p2[1],
1717 };
1718
1719 if self.filled {
1720 unsafe {
1721 sys::ImDrawList_AddRectFilled(
1722 self.draw_list.draw_list,
1723 p1,
1724 p2,
1725 self.color.into(),
1726 self.rounding,
1727 self.flags.bits() as sys::ImDrawFlags,
1728 )
1729 }
1730 } else {
1731 unsafe {
1732 sys::ImDrawList_AddRect(
1733 self.draw_list.draw_list,
1734 p1,
1735 p2,
1736 self.color.into(),
1737 self.rounding,
1738 self.flags.bits() as sys::ImDrawFlags,
1739 self.thickness,
1740 )
1741 }
1742 }
1743 }
1744}
1745
1746#[must_use = "should call .build() to draw the object"]
1748pub struct Circle<'ui> {
1749 center: [f32; 2],
1750 radius: f32,
1751 color: ImColor32,
1752 num_segments: i32,
1753 thickness: f32,
1754 filled: bool,
1755 draw_list: &'ui DrawListMut<'ui>,
1756}
1757
1758impl<'ui> Circle<'ui> {
1759 fn new<C>(
1760 draw_list: &'ui DrawListMut<'_>,
1761 center: impl Into<sys::ImVec2>,
1762 radius: f32,
1763 color: C,
1764 ) -> Self
1765 where
1766 C: Into<ImColor32>,
1767 {
1768 Self {
1769 center: {
1770 let v: sys::ImVec2 = center.into();
1771 v.into()
1772 },
1773 radius,
1774 color: color.into(),
1775 num_segments: 0, thickness: 1.0,
1777 filled: false,
1778 draw_list,
1779 }
1780 }
1781
1782 pub fn thickness(mut self, thickness: f32) -> Self {
1784 self.thickness = thickness;
1785 self
1786 }
1787
1788 pub fn filled(mut self, filled: bool) -> Self {
1790 self.filled = filled;
1791 self
1792 }
1793
1794 pub fn num_segments(mut self, num_segments: i32) -> Self {
1796 self.num_segments = num_segments;
1797 self
1798 }
1799
1800 pub fn build(self) {
1802 let center = sys::ImVec2 {
1803 x: self.center[0],
1804 y: self.center[1],
1805 };
1806
1807 if self.filled {
1808 unsafe {
1809 sys::ImDrawList_AddCircleFilled(
1810 self.draw_list.draw_list,
1811 center,
1812 self.radius,
1813 self.color.into(),
1814 self.num_segments,
1815 )
1816 }
1817 } else {
1818 unsafe {
1819 sys::ImDrawList_AddCircle(
1820 self.draw_list.draw_list,
1821 center,
1822 self.radius,
1823 self.color.into(),
1824 self.num_segments,
1825 self.thickness,
1826 )
1827 }
1828 }
1829 }
1830}
1831
1832#[must_use = "should call .build() to draw the object"]
1834pub struct BezierCurve<'ui> {
1835 pos0: [f32; 2],
1836 cp0: [f32; 2],
1837 pos1: [f32; 2],
1838 cp1: [f32; 2],
1839 color: ImColor32,
1840 thickness: f32,
1841 num_segments: Option<u32>,
1843 draw_list: &'ui DrawListMut<'ui>,
1844}
1845
1846impl<'ui> BezierCurve<'ui> {
1847 pub fn new<C>(
1849 draw_list: &'ui DrawListMut<'_>,
1850 pos0: impl Into<sys::ImVec2>,
1851 cp0: impl Into<sys::ImVec2>,
1852 cp1: impl Into<sys::ImVec2>,
1853 pos1: impl Into<sys::ImVec2>,
1854 c: C,
1855 ) -> Self
1856 where
1857 C: Into<ImColor32>,
1858 {
1859 Self {
1860 pos0: {
1861 let v: sys::ImVec2 = pos0.into();
1862 v.into()
1863 },
1864 cp0: {
1865 let v: sys::ImVec2 = cp0.into();
1866 v.into()
1867 },
1868 cp1: {
1869 let v: sys::ImVec2 = cp1.into();
1870 v.into()
1871 },
1872 pos1: {
1873 let v: sys::ImVec2 = pos1.into();
1874 v.into()
1875 },
1876 color: c.into(),
1877 thickness: 1.0,
1878 num_segments: None,
1879 draw_list,
1880 }
1881 }
1882
1883 pub fn thickness(mut self, thickness: f32) -> Self {
1885 self.thickness = thickness;
1886 self
1887 }
1888
1889 pub fn num_segments(mut self, num_segments: u32) -> Self {
1892 self.num_segments = Some(num_segments);
1893 self
1894 }
1895
1896 pub fn build(self) {
1898 unsafe {
1899 let pos0: sys::ImVec2 = self.pos0.into();
1900 let cp0: sys::ImVec2 = self.cp0.into();
1901 let cp1: sys::ImVec2 = self.cp1.into();
1902 let pos1: sys::ImVec2 = self.pos1.into();
1903
1904 sys::ImDrawList_AddBezierCubic(
1905 self.draw_list.draw_list,
1906 pos0,
1907 cp0,
1908 cp1,
1909 pos1,
1910 self.color.into(),
1911 self.thickness,
1912 self.num_segments.unwrap_or(0) as i32,
1913 )
1914 }
1915 }
1916}
1917
1918#[must_use = "should call .build() to draw the object"]
1920pub struct Polyline<'ui> {
1921 points: Vec<sys::ImVec2>,
1922 thickness: f32,
1923 flags: PolylineFlags,
1924 filled: bool,
1925 color: ImColor32,
1926 draw_list: &'ui DrawListMut<'ui>,
1927}
1928
1929impl<'ui> Polyline<'ui> {
1930 fn new<C, P>(draw_list: &'ui DrawListMut<'_>, points: Vec<P>, c: C) -> Self
1931 where
1932 C: Into<ImColor32>,
1933 P: Into<sys::ImVec2>,
1934 {
1935 Self {
1936 points: points.into_iter().map(Into::into).collect(),
1937 color: c.into(),
1938 thickness: 1.0,
1939 flags: PolylineFlags::NONE,
1940 filled: false,
1941 draw_list,
1942 }
1943 }
1944
1945 pub fn thickness(mut self, thickness: f32) -> Self {
1948 self.thickness = thickness;
1949 self
1950 }
1951
1952 pub fn flags(mut self, flags: PolylineFlags) -> Self {
1954 self.flags = flags;
1955 self
1956 }
1957
1958 pub fn closed(mut self, closed: bool) -> Self {
1960 self.flags.set(PolylineFlags::CLOSED, closed);
1961 self
1962 }
1963
1964 pub fn filled(mut self, filled: bool) -> Self {
1966 self.filled = filled;
1967 self
1968 }
1969
1970 pub fn build(self) {
1972 let count = match i32::try_from(self.points.len()) {
1973 Ok(n) => n,
1974 Err(_) => return,
1975 };
1976 if self.filled {
1977 unsafe {
1978 sys::ImDrawList_AddConvexPolyFilled(
1979 self.draw_list.draw_list,
1980 self.points.as_ptr(),
1981 count,
1982 self.color.into(),
1983 )
1984 }
1985 } else {
1986 unsafe {
1987 sys::ImDrawList_AddPolyline(
1988 self.draw_list.draw_list,
1989 self.points.as_ptr(),
1990 count,
1991 self.color.into(),
1992 self.flags.bits() as sys::ImDrawFlags,
1993 self.thickness,
1994 )
1995 }
1996 }
1997 }
1998}
1999
2000#[must_use = "should call .build() to draw the object"]
2002pub struct Triangle<'ui> {
2003 p1: [f32; 2],
2004 p2: [f32; 2],
2005 p3: [f32; 2],
2006 color: ImColor32,
2007 thickness: f32,
2008 filled: bool,
2009 draw_list: &'ui DrawListMut<'ui>,
2010}
2011
2012impl<'ui> Triangle<'ui> {
2013 fn new<C>(
2014 draw_list: &'ui DrawListMut<'_>,
2015 p1: impl Into<sys::ImVec2>,
2016 p2: impl Into<sys::ImVec2>,
2017 p3: impl Into<sys::ImVec2>,
2018 c: C,
2019 ) -> Self
2020 where
2021 C: Into<ImColor32>,
2022 {
2023 Self {
2024 p1: {
2025 let v: sys::ImVec2 = p1.into();
2026 v.into()
2027 },
2028 p2: {
2029 let v: sys::ImVec2 = p2.into();
2030 v.into()
2031 },
2032 p3: {
2033 let v: sys::ImVec2 = p3.into();
2034 v.into()
2035 },
2036 color: c.into(),
2037 thickness: 1.0,
2038 filled: false,
2039 draw_list,
2040 }
2041 }
2042
2043 pub fn thickness(mut self, thickness: f32) -> Self {
2045 self.thickness = thickness;
2046 self
2047 }
2048
2049 pub fn filled(mut self, filled: bool) -> Self {
2051 self.filled = filled;
2052 self
2053 }
2054
2055 pub fn build(self) {
2057 let p1 = sys::ImVec2 {
2058 x: self.p1[0],
2059 y: self.p1[1],
2060 };
2061 let p2 = sys::ImVec2 {
2062 x: self.p2[0],
2063 y: self.p2[1],
2064 };
2065 let p3 = sys::ImVec2 {
2066 x: self.p3[0],
2067 y: self.p3[1],
2068 };
2069
2070 if self.filled {
2071 unsafe {
2072 sys::ImDrawList_AddTriangleFilled(
2073 self.draw_list.draw_list,
2074 p1,
2075 p2,
2076 p3,
2077 self.color.into(),
2078 )
2079 }
2080 } else {
2081 unsafe {
2082 sys::ImDrawList_AddTriangle(
2083 self.draw_list.draw_list,
2084 p1,
2085 p2,
2086 p3,
2087 self.color.into(),
2088 self.thickness,
2089 )
2090 }
2091 }
2092 }
2093}