dear_imgui/widget/
menu.rs

1use crate::sys;
2use crate::ui::Ui;
3
4/// # Menu Widgets
5impl Ui {
6    /// Creates and starts appending to a full-screen menu bar.
7    ///
8    /// Returns `Some(MainMenuBarToken)` if the menu bar is visible. After content has been
9    /// rendered, the token must be ended by calling `.end()`.
10    ///
11    /// Returns `None` if the menu bar is not visible and no content should be rendered.
12    #[must_use]
13    #[doc(alias = "BeginMainMenuBar")]
14    pub fn begin_main_menu_bar(&self) -> Option<MainMenuBarToken<'_>> {
15        if unsafe { sys::igBeginMainMenuBar() } {
16            Some(MainMenuBarToken::new(self))
17        } else {
18            None
19        }
20    }
21
22    /// Creates and starts appending to a menu bar for a window.
23    ///
24    /// Returns `Some(MenuBarToken)` if the menu bar is visible. After content has been
25    /// rendered, the token must be ended by calling `.end()`.
26    ///
27    /// Returns `None` if the menu bar is not visible and no content should be rendered.
28    #[must_use]
29    #[doc(alias = "BeginMenuBar")]
30    pub fn begin_menu_bar(&self) -> Option<MenuBarToken<'_>> {
31        if unsafe { sys::igBeginMenuBar() } {
32            Some(MenuBarToken::new(self))
33        } else {
34            None
35        }
36    }
37
38    /// Creates a menu and starts appending to it.
39    ///
40    /// Returns `Some(MenuToken)` if the menu is open. After content has been
41    /// rendered, the token must be ended by calling `.end()`.
42    ///
43    /// Returns `None` if the menu is not open and no content should be rendered.
44    #[must_use]
45    #[doc(alias = "BeginMenu")]
46    pub fn begin_menu(&self, label: impl AsRef<str>) -> Option<MenuToken<'_>> {
47        self.begin_menu_with_enabled(label, true)
48    }
49
50    /// Creates a menu with enabled state and starts appending to it.
51    ///
52    /// Returns `Some(MenuToken)` if the menu is open. After content has been
53    /// rendered, the token must be ended by calling `.end()`.
54    ///
55    /// Returns `None` if the menu is not open and no content should be rendered.
56    #[must_use]
57    #[doc(alias = "BeginMenu")]
58    pub fn begin_menu_with_enabled(
59        &self,
60        label: impl AsRef<str>,
61        enabled: bool,
62    ) -> Option<MenuToken<'_>> {
63        let label_ptr = self.scratch_txt(label);
64        if unsafe { sys::igBeginMenu(label_ptr, enabled) } {
65            Some(MenuToken::new(self))
66        } else {
67            None
68        }
69    }
70
71    /// Creates a menu and runs a closure to construct the contents.
72    ///
73    /// Note: the closure is not called if the menu is not visible.
74    ///
75    /// This is the equivalent of [menu_with_enabled](Self::menu_with_enabled)
76    /// with `enabled` set to `true`.
77    #[doc(alias = "BeginMenu")]
78    pub fn menu<F: FnOnce()>(&self, label: impl AsRef<str>, f: F) {
79        self.menu_with_enabled(label, true, f);
80    }
81
82    /// Creates a menu and runs a closure to construct the contents.
83    ///
84    /// Note: the closure is not called if the menu is not visible.
85    #[doc(alias = "BeginMenu")]
86    pub fn menu_with_enabled<F: FnOnce()>(&self, label: impl AsRef<str>, enabled: bool, f: F) {
87        if let Some(_menu) = self.begin_menu_with_enabled(label, enabled) {
88            f();
89        }
90    }
91
92    /// Creates a menu item.
93    ///
94    /// Returns true if the menu item is activated.
95    #[doc(alias = "MenuItem")]
96    pub fn menu_item(&self, label: impl AsRef<str>) -> bool {
97        let label_ptr = self.scratch_txt(label);
98        unsafe { sys::igMenuItemEx(label_ptr, std::ptr::null(), std::ptr::null(), false, true) }
99    }
100
101    /// Creates a menu item with a shortcut.
102    ///
103    /// Returns true if the menu item is activated.
104    #[doc(alias = "MenuItem")]
105    pub fn menu_item_with_shortcut(
106        &self,
107        label: impl AsRef<str>,
108        shortcut: impl AsRef<str>,
109    ) -> bool {
110        let label_ptr = self.scratch_txt(label);
111        let shortcut_ptr = self.scratch_txt(shortcut);
112        unsafe { sys::igMenuItemEx(label_ptr, std::ptr::null(), shortcut_ptr, false, true) }
113    }
114
115    /// Creates a menu item with explicit enabled/selected state.
116    /// Returns true if the menu item is activated.
117    #[doc(alias = "MenuItem")]
118    pub fn menu_item_enabled_selected(
119        &self,
120        label: impl AsRef<str>,
121        shortcut: Option<impl AsRef<str>>,
122        selected: bool,
123        enabled: bool,
124    ) -> bool {
125        let label_ptr = self.scratch_txt(label);
126        let shortcut_ptr = shortcut
127            .as_ref()
128            .map(|s| self.scratch_txt(s.as_ref()))
129            .unwrap_or(std::ptr::null());
130        unsafe { sys::igMenuItem_Bool(label_ptr, shortcut_ptr, selected, enabled) }
131    }
132
133    /// Creates a toggleable menu item bound to `selected` (updated in place).
134    /// Returns true if the menu item is activated.
135    #[doc(alias = "MenuItem")]
136    pub fn menu_item_toggle(
137        &self,
138        label: impl AsRef<str>,
139        shortcut: Option<impl AsRef<str>>,
140        selected: &mut bool,
141        enabled: bool,
142    ) -> bool {
143        let label_ptr = self.scratch_txt(label);
144        let shortcut_ptr = shortcut
145            .as_ref()
146            .map(|s| self.scratch_txt(s.as_ref()))
147            .unwrap_or(std::ptr::null());
148        unsafe { sys::igMenuItem_BoolPtr(label_ptr, shortcut_ptr, selected, enabled) }
149    }
150}
151
152/// Tracks a main menu bar that can be ended by calling `.end()` or by dropping
153#[must_use]
154pub struct MainMenuBarToken<'ui> {
155    ui: &'ui Ui,
156}
157
158impl<'ui> MainMenuBarToken<'ui> {
159    /// Creates a new main menu bar token
160    fn new(ui: &'ui Ui) -> Self {
161        MainMenuBarToken { ui }
162    }
163
164    /// Ends the main menu bar
165    pub fn end(self) {
166        // The drop implementation will handle the actual ending
167    }
168}
169
170impl<'ui> Drop for MainMenuBarToken<'ui> {
171    fn drop(&mut self) {
172        unsafe {
173            sys::igEndMainMenuBar();
174        }
175    }
176}
177
178/// Tracks a menu bar that can be ended by calling `.end()` or by dropping
179#[must_use]
180pub struct MenuBarToken<'ui> {
181    ui: &'ui Ui,
182}
183
184impl<'ui> MenuBarToken<'ui> {
185    /// Creates a new menu bar token
186    fn new(ui: &'ui Ui) -> Self {
187        MenuBarToken { ui }
188    }
189
190    /// Ends the menu bar
191    pub fn end(self) {
192        // The drop implementation will handle the actual ending
193    }
194}
195
196impl<'ui> Drop for MenuBarToken<'ui> {
197    fn drop(&mut self) {
198        unsafe {
199            sys::igEndMenuBar();
200        }
201    }
202}
203
204/// Tracks a menu that can be ended by calling `.end()` or by dropping
205#[must_use]
206pub struct MenuToken<'ui> {
207    ui: &'ui Ui,
208}
209
210impl<'ui> MenuToken<'ui> {
211    /// Creates a new menu token
212    fn new(ui: &'ui Ui) -> Self {
213        MenuToken { ui }
214    }
215
216    /// Ends the menu
217    pub fn end(self) {
218        // The drop implementation will handle the actual ending
219    }
220}
221
222impl<'ui> Drop for MenuToken<'ui> {
223    fn drop(&mut self) {
224        unsafe {
225            sys::igEndMenu();
226        }
227    }
228}