diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 520fb408..535ffc35 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -179,9 +179,6 @@ pub struct Popup<'a> { /// Gap between the anchor and the popup gap: f32, - /// Used later depending on close behavior - widget_clicked_elsewhere: bool, - /// Default width passed to the Area width: Option, sense: Sense, @@ -205,7 +202,6 @@ impl<'a> Popup<'a> { rect_align: RectAlign::BOTTOM_START, alternative_aligns: None, gap: 0.0, - widget_clicked_elsewhere: false, width: None, sense: Sense::click(), layout: Layout::default(), @@ -219,14 +215,12 @@ impl<'a> Popup<'a> { /// /// See [`Self::menu`] and [`Self::context_menu`] for common use cases. pub fn from_response(response: &Response) -> Self { - let mut popup = Self::new( + Self::new( Self::default_response_id(response), response.ctx.clone(), response, response.layer_id, - ); - popup.widget_clicked_elsewhere = response.clicked_elsewhere(); - popup + ) } /// Show a popup relative to some widget, @@ -504,9 +498,14 @@ impl<'a> Popup<'a> { /// Returns `None` if the popup is not open or anchor is `PopupAnchor::Pointer` and there is /// no pointer. pub fn show(self, content: impl FnOnce(&mut Ui) -> R) -> Option> { - let hover_pos = self.ctx.pointer_hover_pos(); - let id = self.id; + // When the popup was just opened with a click we don't want to immediately close it based + // on the `PopupCloseBehavior`, so we need to remember if the popup was already open on + // last frame. A convenient way to check this is to see if we have a response for the `Area` + // from last frame: + let was_open_last_frame = self.ctx.read_response(id).is_some(); + + let hover_pos = self.ctx.pointer_hover_pos(); if let OpenKind::Memory { set } = self.open_kind { match set { Some(SetOpenCommand::Bool(open)) => { @@ -548,7 +547,6 @@ impl<'a> Popup<'a> { rect_align: _, alternative_aligns: _, gap, - widget_clicked_elsewhere, width, sense, layout, @@ -595,10 +593,13 @@ impl<'a> Popup<'a> { frame.show(ui, content).inner }); + // If the popup was just opened with a click, we don't want to immediately close it again. + let close_click = was_open_last_frame && ctx.input(|i| i.pointer.any_click()); + let closed_by_click = match close_behavior { - PopupCloseBehavior::CloseOnClick => widget_clicked_elsewhere, + PopupCloseBehavior::CloseOnClick => close_click, PopupCloseBehavior::CloseOnClickOutside => { - widget_clicked_elsewhere && response.response.clicked_elsewhere() + close_click && response.response.clicked_elsewhere() } PopupCloseBehavior::IgnoreClicks => false, }; diff --git a/crates/egui_demo_lib/src/demo/popups.rs b/crates/egui_demo_lib/src/demo/popups.rs index 6f7152c2..4574d99e 100644 --- a/crates/egui_demo_lib/src/demo/popups.rs +++ b/crates/egui_demo_lib/src/demo/popups.rs @@ -2,8 +2,8 @@ use crate::rust_view_ui; use egui::color_picker::{Alpha, color_picker_color32}; use egui::containers::menu::{MenuConfig, SubMenuButton}; use egui::{ - Align, Align2, ComboBox, Frame, Id, Layout, Popup, PopupCloseBehavior, RectAlign, RichText, - Tooltip, Ui, UiBuilder, include_image, + Align, Align2, Atom, Button, ComboBox, Frame, Id, Layout, Popup, PopupCloseBehavior, RectAlign, + RichText, Tooltip, Ui, UiBuilder, include_image, }; /// Showcase [`Popup`]. @@ -79,13 +79,15 @@ impl PopupsDemo { } else { egui::Color32::WHITE }; - let mut color_button = - SubMenuButton::new(RichText::new("Background").color(text_color)); - color_button.button = color_button.button.fill(self.color); - color_button.button = color_button - .button - .right_text(RichText::new(SubMenuButton::RIGHT_ARROW).color(text_color)); - color_button.ui(ui, |ui| { + + let button = Button::new(( + RichText::new("Background").color(text_color), + Atom::grow(), + RichText::new(SubMenuButton::RIGHT_ARROW).color(text_color), + )) + .fill(self.color); + + SubMenuButton::from_button(button).ui(ui, |ui| { ui.spacing_mut().slider_width = 200.0; color_picker_color32(ui, &mut self.color, Alpha::Opaque); });