Skip to main content

dear_imgui_rs/layout/
clip_rect.rs

1use super::validation::assert_finite_vec2;
2use crate::Ui;
3use crate::scope::{NativeScopePop, NativeScopeToken};
4use crate::sys;
5
6/// Tracks a pushed clip rect that will be popped on drop.
7///
8/// Tokens for the same draw list must be ended in LIFO order. Prefer
9/// [`Ui::with_clip_rect`] for ordinary scoped use.
10#[must_use]
11pub struct ClipRectToken<'ui> {
12    scope: NativeScopeToken<'ui>,
13}
14
15impl ClipRectToken<'_> {
16    /// Pops a clip rect pushed with [`Ui::push_clip_rect`].
17    ///
18    /// # Panics
19    ///
20    /// Panics before FFI if a later UI clip token for the same draw list is active or the token is
21    /// no longer in its originating window `Begin` scope.
22    pub fn end(self) {}
23}
24
25impl Drop for ClipRectToken<'_> {
26    fn drop(&mut self) {
27        self.scope.finish();
28    }
29}
30
31impl Ui {
32    /// Push a clipping rectangle in screen space.
33    #[doc(alias = "PushClipRect")]
34    pub fn push_clip_rect(
35        &self,
36        min: impl Into<[f32; 2]>,
37        max: impl Into<[f32; 2]>,
38        intersect_with_current: bool,
39    ) -> ClipRectToken<'_> {
40        let min = min.into();
41        let max = max.into();
42        assert_finite_vec2("Ui::push_clip_rect()", "min", min);
43        assert_finite_vec2("Ui::push_clip_rect()", "max", max);
44        let min_v = sys::ImVec2 {
45            x: min[0],
46            y: min[1],
47        };
48        let max_v = sys::ImVec2 {
49            x: max[0],
50            y: max[1],
51        };
52        let draw_list = self.run_with_bound_context(|| unsafe {
53            sys::igPushClipRect(min_v, max_v, intersect_with_current);
54            sys::igGetWindowDrawList()
55        });
56        assert!(
57            !draw_list.is_null(),
58            "Ui::push_clip_rect() requires a current window draw list"
59        );
60        ClipRectToken {
61            scope: self
62                .begin_native_scope(NativeScopePop::PopUiClipRect(draw_list), "ClipRectToken"),
63        }
64    }
65
66    /// Run a closure with a clip rect pushed and automatically popped.
67    pub fn with_clip_rect<R>(
68        &self,
69        min: impl Into<[f32; 2]>,
70        max: impl Into<[f32; 2]>,
71        intersect_with_current: bool,
72        f: impl FnOnce() -> R,
73    ) -> R {
74        let token = self.push_clip_rect(min, max, intersect_with_current);
75        let result = f();
76        drop(token);
77        result
78    }
79
80    /// Returns true if the specified rectangle (min,max) is visible (not clipped).
81    #[doc(alias = "IsRectVisible")]
82    pub fn is_rect_visible_min_max(
83        &self,
84        rect_min: impl Into<[f32; 2]>,
85        rect_max: impl Into<[f32; 2]>,
86    ) -> bool {
87        let mn = rect_min.into();
88        let mx = rect_max.into();
89        assert_finite_vec2("Ui::is_rect_visible_min_max()", "rect_min", mn);
90        assert_finite_vec2("Ui::is_rect_visible_min_max()", "rect_max", mx);
91        let mn_v = sys::ImVec2 { x: mn[0], y: mn[1] };
92        let mx_v = sys::ImVec2 { x: mx[0], y: mx[1] };
93        self.run_with_bound_context(|| unsafe { sys::igIsRectVisible_Vec2(mn_v, mx_v) })
94    }
95
96    /// Returns true if a rectangle of given size at the current cursor pos is visible.
97    #[doc(alias = "IsRectVisible")]
98    pub fn is_rect_visible_with_size(&self, size: impl Into<[f32; 2]>) -> bool {
99        let s = size.into();
100        assert_finite_vec2("Ui::is_rect_visible_with_size()", "size", s);
101        let v = sys::ImVec2 { x: s[0], y: s[1] };
102        self.run_with_bound_context(|| unsafe { sys::igIsRectVisible_Nil(v) })
103    }
104}