Skip to main content

dear_imgui_rs/widget/popup/
ui.rs

1use crate::sys;
2use crate::ui::Ui;
3use crate::window::{WindowFlags, validate_window_flags};
4
5use super::context::PopupContextOptions;
6use super::flags::{validate_popup_open_flags, validate_popup_query_flags};
7use super::{ModalPopup, ModalPopupToken, PopupOpenFlags, PopupQueryFlags, PopupToken};
8
9/// # Popup Widgets
10impl Ui {
11    /// Instructs ImGui that a popup is open.
12    ///
13    /// You should **call this function once** while calling any of the following per-frame:
14    ///
15    /// - [`begin_popup`](Self::begin_popup)
16    /// - [`popup`](Self::popup)
17    /// - [`begin_modal_popup`](Self::begin_modal_popup)
18    /// - [`modal_popup`](Self::modal_popup)
19    ///
20    /// The confusing aspect to popups is that ImGui holds control over the popup itself.
21    #[doc(alias = "OpenPopup")]
22    pub fn open_popup(&self, str_id: impl AsRef<str>) {
23        let str_id_ptr = self.scratch_txt(str_id);
24        unsafe { sys::igOpenPopup_Str(str_id_ptr, PopupOpenFlags::NONE.raw()) }
25    }
26
27    /// Instructs ImGui that a popup is open with flags.
28    #[doc(alias = "OpenPopup")]
29    pub fn open_popup_with_flags(&self, str_id: impl AsRef<str>, flags: PopupOpenFlags) {
30        validate_popup_open_flags("Ui::open_popup_with_flags()", flags);
31        let str_id_ptr = self.scratch_txt(str_id);
32        unsafe { sys::igOpenPopup_Str(str_id_ptr, flags.raw()) }
33    }
34
35    /// Opens a popup when the last item is clicked (typically right-click).
36    ///
37    /// If `str_id` is `None`, the popup is associated with the last item ID.
38    #[doc(alias = "OpenPopupOnItemClick")]
39    pub fn open_popup_on_item_click(&self, str_id: Option<&str>) {
40        self.open_popup_on_item_click_with_flags(str_id, PopupContextOptions::new());
41    }
42
43    /// Opens a popup when the last item is clicked, with explicit flags.
44    #[doc(alias = "OpenPopupOnItemClick")]
45    pub fn open_popup_on_item_click_with_flags(
46        &self,
47        str_id: Option<&str>,
48        flags: impl Into<PopupContextOptions>,
49    ) {
50        let options = flags.into();
51        options.validate("Ui::open_popup_on_item_click_with_flags()");
52        let str_id_ptr = str_id
53            .map(|s| self.scratch_txt(s))
54            .unwrap_or(std::ptr::null());
55        unsafe { sys::igOpenPopupOnItemClick(str_id_ptr, options.raw()) }
56    }
57
58    /// Construct a popup that can have any kind of content.
59    ///
60    /// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
61    /// to signal that this popup is active.
62    #[doc(alias = "BeginPopup")]
63    pub fn begin_popup(&self, str_id: impl AsRef<str>) -> Option<PopupToken<'_>> {
64        self.begin_popup_with_flags(str_id, WindowFlags::empty())
65    }
66
67    /// Construct a popup with window flags.
68    #[doc(alias = "BeginPopup")]
69    pub fn begin_popup_with_flags(
70        &self,
71        str_id: impl AsRef<str>,
72        flags: WindowFlags,
73    ) -> Option<PopupToken<'_>> {
74        validate_window_flags("Ui::begin_popup_with_flags()", flags);
75        let str_id_ptr = self.scratch_txt(str_id);
76        let render = unsafe { sys::igBeginPopup(str_id_ptr, flags.bits()) };
77
78        if render {
79            Some(PopupToken::new(self))
80        } else {
81            None
82        }
83    }
84
85    /// Construct a popup that can have any kind of content.
86    ///
87    /// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
88    /// to signal that this popup is active.
89    #[doc(alias = "BeginPopup")]
90    pub fn popup<F>(&self, str_id: impl AsRef<str>, f: F)
91    where
92        F: FnOnce(),
93    {
94        if let Some(_token) = self.begin_popup(str_id) {
95            f();
96        }
97    }
98
99    /// Creates a modal popup.
100    ///
101    /// Modal popups block interaction with the rest of the application until closed.
102    #[doc(alias = "BeginPopupModal")]
103    pub fn begin_modal_popup(&self, name: impl AsRef<str>) -> Option<ModalPopupToken<'_>> {
104        let name_ptr = self.scratch_txt(name);
105        let render = unsafe {
106            sys::igBeginPopupModal(name_ptr, std::ptr::null_mut(), WindowFlags::empty().bits())
107        };
108
109        if render {
110            Some(ModalPopupToken::new(self))
111        } else {
112            None
113        }
114    }
115
116    /// Creates a modal popup with an opened-state tracking variable.
117    ///
118    /// Passing `opened` enables the title-bar close button (X). When clicked, ImGui will set
119    /// `*opened = false` and close the popup.
120    ///
121    /// Notes:
122    /// - You still need to call [`open_popup`](Self::open_popup) once to open the modal.
123    /// - To pass window flags, use [`begin_modal_popup_config`](Self::begin_modal_popup_config).
124    #[doc(alias = "BeginPopupModal")]
125    pub fn begin_modal_popup_with_opened(
126        &self,
127        name: impl AsRef<str>,
128        opened: &mut bool,
129    ) -> Option<ModalPopupToken<'_>> {
130        let name_ptr = self.scratch_txt(name);
131        let opened_ptr = opened as *mut bool;
132        let render =
133            unsafe { sys::igBeginPopupModal(name_ptr, opened_ptr, WindowFlags::empty().bits()) };
134
135        if render {
136            Some(ModalPopupToken::new(self))
137        } else {
138            None
139        }
140    }
141
142    /// Creates a modal popup builder.
143    pub fn begin_modal_popup_config<'a>(&'a self, name: &'a str) -> ModalPopup<'a> {
144        ModalPopup {
145            name,
146            opened: None,
147            flags: WindowFlags::empty(),
148            ui: self,
149        }
150    }
151
152    /// Creates a modal popup and runs a closure to construct the contents.
153    ///
154    /// Returns the result of the closure if the popup is open.
155    pub fn modal_popup<F, R>(&self, name: impl AsRef<str>, f: F) -> Option<R>
156    where
157        F: FnOnce() -> R,
158    {
159        self.begin_modal_popup(name).map(|_token| f())
160    }
161
162    /// Creates a modal popup with an opened-state tracking variable and runs a closure to
163    /// construct the contents.
164    ///
165    /// Returns the result of the closure if the popup is open.
166    pub fn modal_popup_with_opened<F, R>(
167        &self,
168        name: impl AsRef<str>,
169        opened: &mut bool,
170        f: F,
171    ) -> Option<R>
172    where
173        F: FnOnce() -> R,
174    {
175        self.begin_modal_popup_with_opened(name, opened)
176            .map(|_token| f())
177    }
178
179    /// Closes the current popup.
180    #[doc(alias = "CloseCurrentPopup")]
181    pub fn close_current_popup(&self) {
182        unsafe {
183            sys::igCloseCurrentPopup();
184        }
185    }
186
187    /// Returns true if the popup is open.
188    #[doc(alias = "IsPopupOpen")]
189    pub fn is_popup_open(&self, str_id: impl AsRef<str>) -> bool {
190        let str_id_ptr = self.scratch_txt(str_id);
191        unsafe { sys::igIsPopupOpen_Str(str_id_ptr, PopupQueryFlags::NONE.raw()) }
192    }
193
194    /// Returns true if the popup is open with flags.
195    #[doc(alias = "IsPopupOpen")]
196    pub fn is_popup_open_with_flags(
197        &self,
198        str_id: impl AsRef<str>,
199        flags: PopupQueryFlags,
200    ) -> bool {
201        validate_popup_query_flags("Ui::is_popup_open_with_flags()", flags);
202        let str_id_ptr = self.scratch_txt(str_id);
203        unsafe { sys::igIsPopupOpen_Str(str_id_ptr, flags.raw()) }
204    }
205
206    /// Begin a popup context menu for the last item.
207    #[doc(alias = "BeginPopupContextItem")]
208    pub fn begin_popup_context_item(&self) -> Option<PopupToken<'_>> {
209        self.begin_popup_context_item_with_flags(None, PopupContextOptions::new())
210    }
211
212    /// Begin a popup context menu for the last item with a custom label.
213    #[doc(alias = "BeginPopupContextItem")]
214    pub fn begin_popup_context_item_with_label(
215        &self,
216        str_id: Option<&str>,
217    ) -> Option<PopupToken<'_>> {
218        self.begin_popup_context_item_with_flags(str_id, PopupContextOptions::new())
219    }
220
221    /// Begin a popup context menu for the last item with explicit popup flags.
222    #[doc(alias = "BeginPopupContextItem")]
223    pub fn begin_popup_context_item_with_flags(
224        &self,
225        str_id: Option<&str>,
226        flags: impl Into<PopupContextOptions>,
227    ) -> Option<PopupToken<'_>> {
228        let options = flags.into();
229        options.validate("Ui::begin_popup_context_item_with_flags()");
230        let str_id_ptr = str_id
231            .map(|s| self.scratch_txt(s))
232            .unwrap_or(std::ptr::null());
233
234        let render = unsafe { sys::igBeginPopupContextItem(str_id_ptr, options.raw()) };
235
236        render.then(|| PopupToken::new(self))
237    }
238
239    /// Begin a popup context menu for the current window.
240    #[doc(alias = "BeginPopupContextWindow")]
241    pub fn begin_popup_context_window(&self) -> Option<PopupToken<'_>> {
242        self.begin_popup_context_window_with_flags(None, PopupContextOptions::new())
243    }
244
245    /// Begin a popup context menu for the current window with a custom label.
246    #[doc(alias = "BeginPopupContextWindow")]
247    pub fn begin_popup_context_window_with_label(
248        &self,
249        str_id: Option<&str>,
250    ) -> Option<PopupToken<'_>> {
251        self.begin_popup_context_window_with_flags(str_id, PopupContextOptions::new())
252    }
253
254    /// Begin a popup context menu for the current window with explicit popup flags.
255    #[doc(alias = "BeginPopupContextWindow")]
256    pub fn begin_popup_context_window_with_flags(
257        &self,
258        str_id: Option<&str>,
259        flags: impl Into<PopupContextOptions>,
260    ) -> Option<PopupToken<'_>> {
261        let options = flags.into();
262        options.validate("Ui::begin_popup_context_window_with_flags()");
263        let str_id_ptr = str_id
264            .map(|s| self.scratch_txt(s))
265            .unwrap_or(std::ptr::null());
266
267        let render = unsafe { sys::igBeginPopupContextWindow(str_id_ptr, options.raw()) };
268
269        render.then(|| PopupToken::new(self))
270    }
271
272    /// Begin a popup context menu for empty space (void).
273    #[doc(alias = "BeginPopupContextVoid")]
274    pub fn begin_popup_context_void(&self) -> Option<PopupToken<'_>> {
275        self.begin_popup_context_void_with_flags(None, PopupContextOptions::new())
276    }
277
278    /// Begin a popup context menu for empty space with a custom label.
279    #[doc(alias = "BeginPopupContextVoid")]
280    pub fn begin_popup_context_void_with_label(
281        &self,
282        str_id: Option<&str>,
283    ) -> Option<PopupToken<'_>> {
284        self.begin_popup_context_void_with_flags(str_id, PopupContextOptions::new())
285    }
286
287    /// Begin a popup context menu for empty space (void) with explicit popup flags.
288    #[doc(alias = "BeginPopupContextVoid")]
289    pub fn begin_popup_context_void_with_flags(
290        &self,
291        str_id: Option<&str>,
292        flags: impl Into<PopupContextOptions>,
293    ) -> Option<PopupToken<'_>> {
294        let options = flags.into();
295        options.validate("Ui::begin_popup_context_void_with_flags()");
296        let str_id_ptr = str_id
297            .map(|s| self.scratch_txt(s))
298            .unwrap_or(std::ptr::null());
299
300        let render = unsafe { sys::igBeginPopupContextVoid(str_id_ptr, options.raw()) };
301
302        render.then(|| PopupToken::new(self))
303    }
304}