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
155/// Direction for arrow buttons (alias for Direction)
156pub use crate::Direction as ArrowDirection;
157
158impl Ui {
159    /// Creates an invisible button
160    #[doc(alias = "InvisibleButton")]
161    pub fn invisible_button(&self, str_id: impl AsRef<str>, size: impl Into<[f32; 2]>) -> bool {
162        self.invisible_button_flags(str_id, size, crate::widget::ButtonFlags::NONE)
163    }
164
165    /// Creates an invisible button with independent flags.
166    ///
167    /// Use [`Self::invisible_button_options`] to choose a mouse button other
168    /// than the default left button.
169    #[doc(alias = "InvisibleButton")]
170    pub fn invisible_button_flags(
171        &self,
172        str_id: impl AsRef<str>,
173        size: impl Into<[f32; 2]>,
174        flags: crate::widget::ButtonFlags,
175    ) -> bool {
176        validate_invisible_button_flags("Ui::invisible_button_flags()", flags);
177        self.invisible_button_raw(str_id, size, flags.bits())
178    }
179
180    /// Creates an invisible button with complete options.
181    #[doc(alias = "InvisibleButton")]
182    pub fn invisible_button_options(
183        &self,
184        str_id: impl AsRef<str>,
185        size: impl Into<[f32; 2]>,
186        options: impl Into<crate::widget::InvisibleButtonOptions>,
187    ) -> bool {
188        let options = options.into();
189        validate_invisible_button_options("Ui::invisible_button_options()", options);
190        self.invisible_button_raw(str_id, size, options.raw())
191    }
192
193    fn invisible_button_raw(
194        &self,
195        str_id: impl AsRef<str>,
196        size: impl Into<[f32; 2]>,
197        flags: i32,
198    ) -> bool {
199        let id_ptr = self.scratch_txt(str_id);
200        let size = size.into();
201        assert_finite_vec2("Ui::invisible_button()", "size", size);
202        let size_vec: sys::ImVec2 = size.into();
203        unsafe { sys::igInvisibleButton(id_ptr, size_vec, flags) }
204    }
205
206    /// Creates an arrow button
207    #[doc(alias = "ArrowButton")]
208    pub fn arrow_button(&self, str_id: impl AsRef<str>, dir: crate::Direction) -> bool {
209        validate_arrow_direction("Ui::arrow_button()", dir);
210        let id_ptr = self.scratch_txt(str_id);
211        unsafe { sys::igArrowButton(id_ptr, dir as i32) }
212    }
213}