From 34b5b211b3ea5189bf47ade392aa06c046ace0e6 Mon Sep 17 00:00:00 2001 From: Lucas Meurer Date: Mon, 3 Mar 2025 17:03:48 +0100 Subject: [PATCH] Allow opening multiple popups --- crates/egui/src/containers/popup.rs | 4 ++-- crates/egui/src/memory/mod.rs | 29 +++++++++++++++---------- crates/egui/src/widgets/color_picker.rs | 2 +- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 4a457bf03..efc261f69 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -519,7 +519,7 @@ impl<'a> Popup<'a> { _ => mem.open_popup(id), } } else { - mem.close_popup(); + mem.close_popup(id); } } Some(SetOpenCommand::Toggle) => { @@ -599,7 +599,7 @@ impl<'a> Popup<'a> { } OpenKind::Memory { .. } => { if should_close { - ctx.memory_mut(|mem| mem.close_popup()); + ctx.memory_mut(|mem| mem.close_popup(id)); } } } diff --git a/crates/egui/src/memory/mod.rs b/crates/egui/src/memory/mod.rs index d38e39f75..2980df584 100644 --- a/crates/egui/src/memory/mod.rs +++ b/crates/egui/src/memory/mod.rs @@ -94,7 +94,7 @@ pub struct Memory { /// If position is [`None`], the popup position will be calculated based on some configuration /// (e.g. relative to some other widget). #[cfg_attr(feature = "persistence", serde(skip))] - popup: Option<(Id, Option)>, + popup: Vec<(Id, Option)>, #[cfg_attr(feature = "persistence", serde(skip))] everything_is_visible: bool, @@ -1070,37 +1070,42 @@ impl Memory { /// ## Popups /// Popups are things like combo-boxes, color pickers, menus etc. -/// Only one can be open at a time. impl Memory { /// Is the given popup open? pub fn is_popup_open(&self, popup_id: Id) -> bool { - self.popup.is_some_and(|(id, _)| id == popup_id) || self.everything_is_visible() + self.popup.iter().any(|(id, _)| id == &popup_id) || self.everything_is_visible() } /// Is any popup open? pub fn any_popup_open(&self) -> bool { - self.popup.is_some() || self.everything_is_visible() + !self.popup.is_empty() || self.everything_is_visible() } - /// Open the given popup and close all others. + /// Open the given popup. pub fn open_popup(&mut self, popup_id: Id) { - self.popup = Some((popup_id, None)); + self.popup.push((popup_id, None)); } /// Open the popup and remember its position. pub fn open_popup_at(&mut self, popup_id: Id, pos: impl Into>) { - self.popup = Some((popup_id, pos.into())); + self.popup.push((popup_id, pos.into())); } /// Get the position for this popup. pub fn popup_position(&self, id: Id) -> Option { self.popup - .and_then(|(popup_id, pos)| if popup_id == id { pos } else { None }) + .iter() + .find_map(|(popup_id, pos)| if *popup_id == id { *pos } else { None }) } - /// Close the open popup, if any. - pub fn close_popup(&mut self) { - self.popup = None; + /// Close the popup with the given id. + pub fn close_popup(&mut self, id: Id) { + self.popup.retain(|(popup_id, _)| *popup_id != id); + } + + /// Close all popups. + pub fn close_all_popups(&mut self) { + self.popup.clear(); } /// Toggle the given popup between closed and open. @@ -1108,7 +1113,7 @@ impl Memory { /// Note: At most, only one popup can be open at a time. pub fn toggle_popup(&mut self, popup_id: Id) { if self.is_popup_open(popup_id) { - self.close_popup(); + self.close_popup(popup_id); } else { self.open_popup(popup_id); } diff --git a/crates/egui/src/widgets/color_picker.rs b/crates/egui/src/widgets/color_picker.rs index a9906cef1..500fb0b88 100644 --- a/crates/egui/src/widgets/color_picker.rs +++ b/crates/egui/src/widgets/color_picker.rs @@ -521,7 +521,7 @@ pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva, alpha: Alpha) -> Res if !button_response.clicked() && (ui.input(|i| i.key_pressed(Key::Escape)) || area_response.clicked_elsewhere()) { - ui.memory_mut(|mem| mem.close_popup()); + ui.memory_mut(|mem| mem.close_popup(popup_id)); } }