Skip to main content

dear_imgui_rs/widget/misc/
invisible_button.rs

1use super::validation::assert_finite_vec2;
2use crate::Ui;
3use crate::sys;
4
5fn validate_invisible_button_flags(caller: &str, flags: ButtonFlags) {
6    let unsupported = flags.bits() & !ButtonFlags::all().bits();
7    assert!(
8        unsupported == 0,
9        "{caller} received unsupported ImGuiButtonFlags bits: 0x{unsupported:X}"
10    );
11}
12
13fn validate_invisible_button_options(caller: &str, options: InvisibleButtonOptions) {
14    validate_invisible_button_flags(caller, options.flags);
15    let unsupported_buttons =
16        options.mouse_buttons.bits() & !InvisibleButtonMouseButtons::all().bits();
17    assert!(
18        unsupported_buttons == 0,
19        "{caller} received unsupported ImGuiButtonFlags mouse-button bits: 0x{unsupported_buttons:X}"
20    );
21    assert!(
22        !options.mouse_buttons.is_empty(),
23        "{caller} requires at least one invisible-button mouse button"
24    );
25}
26
27fn validate_arrow_direction(caller: &str, dir: crate::Direction) {
28    assert!(
29        matches!(
30            dir,
31            crate::Direction::Left
32                | crate::Direction::Right
33                | crate::Direction::Up
34                | crate::Direction::Down
35        ),
36        "{caller} direction must be Left, Right, Up, or Down"
37    );
38}
39
40bitflags::bitflags! {
41    /// Independent flags for invisible buttons.
42    ///
43    /// Mouse-button selection is represented separately by
44    /// [`InvisibleButtonMouseButtons`] / [`InvisibleButtonOptions`].
45    #[repr(transparent)]
46    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
47    pub struct ButtonFlags: i32 {
48        /// No flags
49        const NONE = 0;
50        /// Allow interaction overlap with following items.
51        const ALLOW_OVERLAP = sys::ImGuiButtonFlags_AllowOverlap as i32;
52        /// Keep navigation/tabbing enabled for this invisible button.
53        const ENABLE_NAV = sys::ImGuiButtonFlags_EnableNav as i32;
54    }
55}
56
57bitflags::bitflags! {
58    /// Mouse buttons accepted by invisible buttons.
59    #[repr(transparent)]
60    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
61    pub struct InvisibleButtonMouseButtons: i32 {
62        /// React on left mouse button.
63        const LEFT = sys::ImGuiButtonFlags_MouseButtonLeft as i32;
64        /// React on right mouse button.
65        const RIGHT = sys::ImGuiButtonFlags_MouseButtonRight as i32;
66        /// React on middle mouse button.
67        const MIDDLE = sys::ImGuiButtonFlags_MouseButtonMiddle as i32;
68    }
69}
70
71impl Default for InvisibleButtonMouseButtons {
72    fn default() -> Self {
73        Self::LEFT
74    }
75}
76
77impl From<crate::MouseButton> for InvisibleButtonMouseButtons {
78    fn from(button: crate::MouseButton) -> Self {
79        match button {
80            crate::MouseButton::Left => Self::LEFT,
81            crate::MouseButton::Right => Self::RIGHT,
82            crate::MouseButton::Middle => Self::MIDDLE,
83            crate::MouseButton::Extra1 | crate::MouseButton::Extra2 => {
84                panic!("Dear ImGui invisible buttons only support left, right, and middle buttons")
85            }
86        }
87    }
88}
89
90/// Complete options accepted by `InvisibleButton()`.
91#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
92pub struct InvisibleButtonOptions {
93    pub flags: ButtonFlags,
94    pub mouse_buttons: InvisibleButtonMouseButtons,
95}
96
97impl InvisibleButtonOptions {
98    pub const fn new() -> Self {
99        Self {
100            flags: ButtonFlags::NONE,
101            mouse_buttons: InvisibleButtonMouseButtons::LEFT,
102        }
103    }
104
105    pub fn flags(mut self, flags: ButtonFlags) -> Self {
106        self.flags = flags;
107        self
108    }
109
110    pub fn mouse_buttons(mut self, buttons: InvisibleButtonMouseButtons) -> Self {
111        self.mouse_buttons = buttons;
112        self
113    }
114
115    pub fn mouse_button(mut self, button: crate::MouseButton) -> Self {
116        self.mouse_buttons = button.into();
117        self
118    }
119
120    /// Returns the raw `ImGuiButtonFlags` bits assembled for `InvisibleButton()`.
121    pub fn bits(self) -> i32 {
122        self.raw()
123    }
124
125    #[inline]
126    pub(crate) fn raw(self) -> i32 {
127        self.flags.bits() | self.mouse_buttons.bits()
128    }
129}
130
131impl Default for InvisibleButtonOptions {
132    fn default() -> Self {
133        Self::new()
134    }
135}
136
137impl From<ButtonFlags> for InvisibleButtonOptions {
138    fn from(flags: ButtonFlags) -> Self {
139        Self::new().flags(flags)
140    }
141}
142
143impl From<InvisibleButtonMouseButtons> for InvisibleButtonOptions {
144    fn from(buttons: InvisibleButtonMouseButtons) -> Self {
145        Self::new().mouse_buttons(buttons)
146    }
147}
148
149impl From<crate::MouseButton> for InvisibleButtonOptions {
150    fn from(button: crate::MouseButton) -> Self {
151        Self::new().mouse_button(button)
152    }
153}
154
155impl Ui {
156    /// Creates an invisible button
157    #[doc(alias = "InvisibleButton")]
158    pub fn invisible_button(&self, str_id: impl AsRef<str>, size: impl Into<[f32; 2]>) -> bool {
159        self.invisible_button_flags(str_id, size, crate::widget::ButtonFlags::NONE)
160    }
161
162    /// Creates an invisible button with independent flags.
163    ///
164    /// Use [`Self::invisible_button_options`] to choose a mouse button other
165    /// than the default left button.
166    #[doc(alias = "InvisibleButton")]
167    pub fn invisible_button_flags(
168        &self,
169        str_id: impl AsRef<str>,
170        size: impl Into<[f32; 2]>,
171        flags: crate::widget::ButtonFlags,
172    ) -> bool {
173        validate_invisible_button_flags("Ui::invisible_button_flags()", flags);
174        self.invisible_button_raw(str_id, size, flags.bits())
175    }
176
177    /// Creates an invisible button with complete options.
178    #[doc(alias = "InvisibleButton")]
179    pub fn invisible_button_options(
180        &self,
181        str_id: impl AsRef<str>,
182        size: impl Into<[f32; 2]>,
183        options: impl Into<crate::widget::InvisibleButtonOptions>,
184    ) -> bool {
185        let options = options.into();
186        validate_invisible_button_options("Ui::invisible_button_options()", options);
187        self.invisible_button_raw(str_id, size, options.raw())
188    }
189
190    fn invisible_button_raw(
191        &self,
192        str_id: impl AsRef<str>,
193        size: impl Into<[f32; 2]>,
194        flags: i32,
195    ) -> bool {
196        let id_ptr = self.scratch_txt(str_id);
197        let size = size.into();
198        assert_finite_vec2("Ui::invisible_button()", "size", size);
199        let size_vec: sys::ImVec2 = size.into();
200        self.run_with_bound_context(|| unsafe { sys::igInvisibleButton(id_ptr, size_vec, flags) })
201    }
202
203    /// Creates an arrow button
204    #[doc(alias = "ArrowButton")]
205    pub fn arrow_button(&self, str_id: impl AsRef<str>, dir: crate::Direction) -> bool {
206        validate_arrow_direction("Ui::arrow_button()", dir);
207        let id_ptr = self.scratch_txt(str_id);
208        self.run_with_bound_context(|| unsafe { sys::igArrowButton(id_ptr, dir as i32) })
209    }
210}