arcdps_imgui\widget/
menu.rs

1// use crate::string::ImStr;
2use crate::sys;
3use crate::Ui;
4
5/// # Widgets: Menus
6impl<'ui> Ui<'ui> {
7    /// Creates and starts appending to a full-screen menu bar.
8    ///
9    /// Returns `Some(MainMenuBarToken)` if the menu bar is visible. After content has been
10    /// rendered, the token must be ended by calling `.end()`.
11    ///
12    /// Returns `None` if the menu bar is not visible and no content should be rendered.
13    #[must_use]
14    #[doc(alias = "BeginMainMenuBar")]
15    pub fn begin_main_menu_bar(&self) -> Option<MainMenuBarToken<'ui>> {
16        if unsafe { sys::igBeginMainMenuBar() } {
17            Some(MainMenuBarToken::new(self))
18        } else {
19            None
20        }
21    }
22    /// Creates a full-screen main menu bar and runs a closure to construct the contents.
23    ///
24    /// Note: the closure is not called if the menu bar is not visible.
25    #[doc(alias = "BeginMenuBar")]
26    pub fn main_menu_bar<F: FnOnce()>(&self, f: F) {
27        if let Some(_menu_bar) = self.begin_main_menu_bar() {
28            f();
29        }
30    }
31    /// Creates and starts appending to the menu bar of the current window.
32    ///
33    /// Returns `Some(MenuBarToken)` if the menu bar is visible. After content has been
34    /// rendered, the token must be ended by calling `.end()`.
35    ///
36    /// Returns `None` if the menu bar is not visible and no content should be rendered.
37    #[must_use]
38    #[doc(alias = "BeginMenuBar")]
39    pub fn begin_menu_bar(&self) -> Option<MenuBarToken<'_>> {
40        if unsafe { sys::igBeginMenuBar() } {
41            Some(MenuBarToken::new(self))
42        } else {
43            None
44        }
45    }
46    /// Creates a menu bar in the current window and runs a closure to construct the contents.
47    ///
48    /// Note: the closure is not called if the menu bar is not visible.
49    #[doc(alias = "BeginMenuBar")]
50    pub fn menu_bar<F: FnOnce()>(&self, f: F) {
51        if let Some(_menu_bar) = self.begin_menu_bar() {
52            f();
53        }
54    }
55
56    /// Creates and starts appending to a sub-menu entry.
57    ///
58    /// Returns `Some(MenuToken)` if the menu is visible. After content has been
59    /// rendered, the token must be ended by calling `.end()`.
60    ///
61    /// Returns `None` if the menu is not visible and no content should be rendered.
62    ///
63    /// This is the equivalent of [begin_menu_with_enabled](Self::begin_menu_with_enabled)
64    /// with `enabled` set to `true`.
65    #[must_use]
66    #[doc(alias = "BeginMenu")]
67    pub fn begin_menu(&self, label: impl AsRef<str>) -> Option<MenuToken<'_>> {
68        self.begin_menu_with_enabled(label, true)
69    }
70
71    /// Creates and starts appending to a sub-menu entry.
72    ///
73    /// Returns `Some(MenuToken)` if the menu is visible. After content has been
74    /// rendered, the token must be ended by calling `.end()`.
75    ///
76    /// Returns `None` if the menu is not visible and no content should be rendered.
77    #[must_use]
78    #[doc(alias = "BeginMenu")]
79    pub fn begin_menu_with_enabled(
80        &self,
81        label: impl AsRef<str>,
82        enabled: bool,
83    ) -> Option<MenuToken<'_>> {
84        if unsafe { sys::igBeginMenu(self.scratch_txt(label), enabled) } {
85            Some(MenuToken::new(self))
86        } else {
87            None
88        }
89    }
90    /// Creates a menu and runs a closure to construct the contents.
91    ///
92    /// Note: the closure is not called if the menu is not visible.
93    ///
94    /// This is the equivalent of [menu_with_enabled](Self::menu_with_enabled)
95    /// with `enabled` set to `true`.
96    #[doc(alias = "BeginMenu")]
97    pub fn menu<F: FnOnce()>(&self, label: impl AsRef<str>, f: F) {
98        self.menu_with_enabled(label, true, f);
99    }
100
101    /// Creates a menu and runs a closure to construct the contents.
102    ///
103    /// Note: the closure is not called if the menu is not visible.
104    #[doc(alias = "BeginMenu")]
105    pub fn menu_with_enabled<F: FnOnce()>(&self, label: impl AsRef<str>, enabled: bool, f: F) {
106        if let Some(_menu) = self.begin_menu_with_enabled(label, enabled) {
107            f();
108        }
109    }
110}
111
112/// Builder for a menu item.
113#[derive(Copy, Clone, Debug)]
114#[must_use]
115pub struct MenuItem<Label, Shortcut = &'static str> {
116    label: Label,
117    shortcut: Option<Shortcut>,
118    selected: bool,
119    enabled: bool,
120}
121
122impl<Label: AsRef<str>> MenuItem<Label> {
123    /// Construct a new menu item builder.
124    pub fn new(label: Label) -> Self {
125        MenuItem {
126            label,
127            shortcut: None,
128            selected: false,
129            enabled: true,
130        }
131    }
132}
133
134impl<Label: AsRef<str>, Shortcut: AsRef<str>> MenuItem<Label, Shortcut> {
135    /// Sets the menu item shortcut.
136    ///
137    /// Shortcuts are displayed for convenience only and are not automatically handled.
138    #[inline]
139    pub fn shortcut<Shortcut2: AsRef<str>>(
140        self,
141        shortcut: Shortcut2,
142    ) -> MenuItem<Label, Shortcut2> {
143        MenuItem {
144            label: self.label,
145            shortcut: Some(shortcut),
146            selected: self.selected,
147            enabled: self.enabled,
148        }
149    }
150    /// Sets the selected state of the menu item.
151    ///
152    /// Default: false
153    #[inline]
154    pub fn selected(mut self, selected: bool) -> Self {
155        self.selected = selected;
156        self
157    }
158    /// Enables/disables the menu item.
159    ///
160    /// Default: enabled
161    #[inline]
162    pub fn enabled(mut self, enabled: bool) -> Self {
163        self.enabled = enabled;
164        self
165    }
166    /// Builds the menu item.
167    ///
168    /// Returns true if the menu item is activated.
169    #[doc(alias = "MenuItemBool")]
170    pub fn build(self, ui: &Ui<'_>) -> bool {
171        unsafe {
172            let (label, shortcut) = ui.scratch_txt_with_opt(self.label, self.shortcut);
173            sys::igMenuItem_Bool(label, shortcut, self.selected, self.enabled)
174        }
175    }
176
177    #[doc(alias = "MenuItemBool")]
178    /// Builds the menu item using a mutable reference to selected state.
179    pub fn build_with_ref(self, ui: &Ui<'_>, selected: &mut bool) -> bool {
180        if self.selected(*selected).build(ui) {
181            *selected = !*selected;
182            true
183        } else {
184            false
185        }
186    }
187}
188
189create_token!(
190    /// Tracks a main menu bar that can be ended by calling `.end()`
191    /// or by dropping
192    pub struct MainMenuBarToken<'ui>;
193
194    /// Ends a main menu bar
195    drop { sys::igEndMainMenuBar() }
196);
197
198create_token!(
199    /// Tracks a menu bar that can be ended by calling `.end()`
200    /// or by dropping
201    pub struct MenuBarToken<'ui>;
202
203    /// Ends a menu bar
204    drop { sys::igEndMenuBar() }
205);
206
207create_token!(
208    /// Tracks a menu that can be ended by calling `.end()`
209    /// or by dropping
210    pub struct MenuToken<'ui>;
211
212    /// Ends a menu
213    drop { sys::igEndMenu() }
214);