Added Context::is_context_menu_open() (#3267)
I encountered a case where I needed to know if an egui context menu was open, even if the mouse cursor was not in an egui area (full details in discord). I found that every resource I needed to detect that the menu was open was either private, or pub(crate). While it is possible to wrap the `Response::context_menu()` in code to do state-tracking, it becomes necessary to duplicate that code in every place you use a context menu. In this commit, I add `Context::is_context_menu_open()`. Named similarly to `Context::is_pointer_over_area()`, this method will return true if any context menu is open. This is possible because the context menu uses a temp var with a fixed Id to store its state. This method just fetches the state, and interrogates it to see if there is a menu present. One helper method, `BarState::has_root()`, was added as all the fields needed to perform the check were private to the `menu` module. I've also updated the Context Menu demo to show the result of `is_context_menu_open()` to verify the code functions as expected.
This commit is contained in:
parent
461328f54d
commit
32a63da580
|
|
@ -1389,6 +1389,14 @@ impl Context {
|
|||
pub fn highlight_widget(&self, id: Id) {
|
||||
self.frame_state_mut(|fs| fs.highlight_next_frame.insert(id));
|
||||
}
|
||||
|
||||
/// Is an egui context menu open?
|
||||
pub fn is_context_menu_open(&self) -> bool {
|
||||
self.data(|d| {
|
||||
d.get_temp::<crate::menu::BarState>(menu::CONTEXT_MENU_ID_STR.into())
|
||||
.map_or(false, |state| state.has_root())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Ergonomic methods to forward some calls often used in 'if let' without holding the borrow
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ impl BarState {
|
|||
MenuRoot::stationary_click_interaction(response, &mut self.open_menu, response.id);
|
||||
self.open_menu.show(response, add_contents)
|
||||
}
|
||||
|
||||
pub(crate) fn has_root(&self) -> bool {
|
||||
self.open_menu.inner.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for BarState {
|
||||
|
|
@ -212,12 +216,14 @@ fn stationary_menu_image_impl<'c, R>(
|
|||
InnerResponse::new(inner.map(|r| r.inner), button_response)
|
||||
}
|
||||
|
||||
pub(crate) const CONTEXT_MENU_ID_STR: &str = "__egui::context_menu";
|
||||
|
||||
/// Response to secondary clicks (right-clicks) by showing the given menu.
|
||||
pub(crate) fn context_menu(
|
||||
response: &Response,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> Option<InnerResponse<()>> {
|
||||
let menu_id = Id::new("__egui::context_menu");
|
||||
let menu_id = Id::new(CONTEXT_MENU_ID_STR);
|
||||
let mut bar_state = BarState::load(&response.ctx, menu_id);
|
||||
|
||||
MenuRoot::context_click_interaction(response, &mut bar_state, response.id);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@ impl super::View for ContextMenus {
|
|||
ui.menu_button("Click for menu", Self::nested_menus);
|
||||
ui.button("Right-click for menu")
|
||||
.context_menu(Self::nested_menus);
|
||||
if ui.ctx().is_context_menu_open() {
|
||||
ui.label("Context menu is open");
|
||||
} else {
|
||||
ui.label("Context menu is closed");
|
||||
}
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
|
|
|||
Loading…
Reference in New Issue