Give each menu `Area` an id distinct from the id of what was clicked (#4114)

* Closes https://github.com/emilk/egui/issues/4113

Previously the `Id` of the menu `Area` was using the same id as the
thing that was clicked (i.e. the button opening menu), which lead to id
clashes
This commit is contained in:
Emil Ernerfeldt 2024-02-29 14:18:06 +01:00 committed by GitHub
parent e8af6f38fc
commit 86d7f296ae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 21 additions and 21 deletions

View File

@ -39,13 +39,14 @@ impl BarState {
} }
/// Show a menu at pointer if primary-clicked response. /// Show a menu at pointer if primary-clicked response.
///
/// Should be called from [`Context`] on a [`Response`] /// Should be called from [`Context`] on a [`Response`]
pub fn bar_menu<R>( pub fn bar_menu<R>(
&mut self, &mut self,
response: &Response, response: &Response,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<InnerResponse<R>> { ) -> Option<InnerResponse<R>> {
MenuRoot::stationary_click_interaction(response, &mut self.open_menu, response.id); MenuRoot::stationary_click_interaction(response, &mut self.open_menu);
self.open_menu.show(response, add_contents) self.open_menu.show(response, add_contents)
} }
@ -134,7 +135,7 @@ pub(crate) fn submenu_button<R>(
/// wrapper for the contents of every menu. /// wrapper for the contents of every menu.
pub(crate) fn menu_ui<'c, R>( pub(crate) fn menu_ui<'c, R>(
ctx: &Context, ctx: &Context,
menu_id: impl Into<Id>, menu_id: Id,
menu_state_arc: &Arc<RwLock<MenuState>>, menu_state_arc: &Arc<RwLock<MenuState>>,
add_contents: impl FnOnce(&mut Ui) -> R + 'c, add_contents: impl FnOnce(&mut Ui) -> R + 'c,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
@ -144,7 +145,7 @@ pub(crate) fn menu_ui<'c, R>(
menu_state.rect.min menu_state.rect.min
}; };
let area = Area::new(menu_id) let area = Area::new(menu_id.with("__menu"))
.order(Order::Foreground) .order(Order::Foreground)
.fixed_pos(pos) .fixed_pos(pos)
.constrain_to(ctx.screen_rect()) .constrain_to(ctx.screen_rect())
@ -222,7 +223,7 @@ pub(crate) fn context_menu(
let menu_id = Id::new(CONTEXT_MENU_ID_STR); let menu_id = Id::new(CONTEXT_MENU_ID_STR);
let mut bar_state = BarState::load(&response.ctx, menu_id); let mut bar_state = BarState::load(&response.ctx, menu_id);
MenuRoot::context_click_interaction(response, &mut bar_state, response.id); MenuRoot::context_click_interaction(response, &mut bar_state);
let inner_response = bar_state.show(response, add_contents); let inner_response = bar_state.show(response, add_contents);
bar_state.store(&response.ctx, menu_id); bar_state.store(&response.ctx, menu_id);
@ -237,6 +238,7 @@ pub(crate) struct MenuRootManager {
impl MenuRootManager { impl MenuRootManager {
/// Show a menu at pointer if right-clicked response. /// Show a menu at pointer if right-clicked response.
///
/// Should be called from [`Context`] on a [`Response`] /// Should be called from [`Context`] on a [`Response`]
pub fn show<R>( pub fn show<R>(
&mut self, &mut self,
@ -308,11 +310,9 @@ impl MenuRoot {
/// Interaction with a stationary menu, i.e. fixed in another Ui. /// Interaction with a stationary menu, i.e. fixed in another Ui.
/// ///
/// Responds to primary clicks. /// Responds to primary clicks.
fn stationary_interaction( fn stationary_interaction(response: &Response, root: &mut MenuRootManager) -> MenuResponse {
response: &Response, let id = response.id;
root: &mut MenuRootManager,
id: Id,
) -> MenuResponse {
if (response.clicked() && root.is_menu_open(id)) if (response.clicked() && root.is_menu_open(id))
|| response.ctx.input(|i| i.key_pressed(Key::Escape)) || response.ctx.input(|i| i.key_pressed(Key::Escape))
{ {
@ -357,8 +357,8 @@ impl MenuRoot {
MenuResponse::Stay MenuResponse::Stay
} }
/// Interaction with a context menu (secondary clicks). /// Interaction with a context menu (secondary click).
fn context_interaction(response: &Response, root: &mut Option<Self>, id: Id) -> MenuResponse { fn context_interaction(response: &Response, root: &mut Option<Self>) -> MenuResponse {
let response = response.interact(Sense::click()); let response = response.interact(Sense::click());
response.ctx.input(|input| { response.ctx.input(|input| {
let pointer = &input.pointer; let pointer = &input.pointer;
@ -371,7 +371,7 @@ impl MenuRoot {
} }
if !in_old_menu { if !in_old_menu {
if response.hovered() && response.secondary_clicked() { if response.hovered() && response.secondary_clicked() {
return MenuResponse::Create(pos, id); return MenuResponse::Create(pos, response.id);
} else if (response.hovered() && pointer.primary_down()) || destroy { } else if (response.hovered() && pointer.primary_down()) || destroy {
return MenuResponse::Close; return MenuResponse::Close;
} }
@ -392,14 +392,14 @@ impl MenuRoot {
} }
/// Respond to secondary (right) clicks. /// Respond to secondary (right) clicks.
pub fn context_click_interaction(response: &Response, root: &mut MenuRootManager, id: Id) { pub fn context_click_interaction(response: &Response, root: &mut MenuRootManager) {
let menu_response = Self::context_interaction(response, root, id); let menu_response = Self::context_interaction(response, root);
Self::handle_menu_response(root, menu_response); Self::handle_menu_response(root, menu_response);
} }
// Responds to primary clicks. // Responds to primary clicks.
pub fn stationary_click_interaction(response: &Response, root: &mut MenuRootManager, id: Id) { pub fn stationary_click_interaction(response: &Response, root: &mut MenuRootManager) {
let menu_response = Self::stationary_interaction(response, root, id); let menu_response = Self::stationary_interaction(response, root);
Self::handle_menu_response(root, menu_response); Self::handle_menu_response(root, menu_response);
} }
} }

View File

@ -105,17 +105,17 @@ impl WidgetRects {
// e.g. calling `response.interact(…)` to add more interaction. // e.g. calling `response.interact(…)` to add more interaction.
let (idx_in_layer, existing) = entry.get_mut(); let (idx_in_layer, existing) = entry.get_mut();
egui_assert!(
existing.layer_id == widget_rect.layer_id,
"Widget changed layer_id during the frame"
);
// Update it: // Update it:
existing.rect = widget_rect.rect; // last wins existing.rect = widget_rect.rect; // last wins
existing.interact_rect = widget_rect.interact_rect; // last wins existing.interact_rect = widget_rect.interact_rect; // last wins
existing.sense |= widget_rect.sense; existing.sense |= widget_rect.sense;
existing.enabled |= widget_rect.enabled; existing.enabled |= widget_rect.enabled;
egui_assert!(
existing.layer_id == widget_rect.layer_id,
"Widget changed layer_id during the frame"
);
if existing.layer_id == widget_rect.layer_id { if existing.layer_id == widget_rect.layer_id {
layer_widgets[*idx_in_layer] = *existing; layer_widgets[*idx_in_layer] = *existing;
} }