Fix manual `Popup` not closing (#7383)
Fixes manually created popups (via `Popup::new`) not closing, since
widget_clicked_elsewhere was always false.
This example would never close:
```rs
let mut open = true;
eframe::run_simple_native("My egui App", options, move |ctx, _frame| {
egui::CentralPanel::default().show(ctx, |ui| {
let response = egui::Popup::new(
Id::new("popup"),
ctx.clone(),
PopupAnchor::Position(Pos2::new(10.0, 10.0)),
LayerId::new(Order::Foreground, Id::new("popup")),
)
.open(open)
.show(|ui| {
ui.label("This is a popup!");
ui.label("You can put anything in here.");
});
if let Some(response) = response {
if response.response.should_close() {
open = false;
}
}
});
})
```
I also noticed that the Color submenu in the popups example had a double
arrow (must have been broken in the atoms PR):
<img width="248" height="110" alt="Screenshot 2025-08-07 at 13 42 28"
src="https://github.com/user-attachments/assets/a4e0c267-ae71-4b2c-a1f0-f53f9662d026"
/>
Also fixed this in the PR.
This commit is contained in:
parent
36a4981f29
commit
e8e99a0bb6
|
|
@ -179,9 +179,6 @@ pub struct Popup<'a> {
|
||||||
/// Gap between the anchor and the popup
|
/// Gap between the anchor and the popup
|
||||||
gap: f32,
|
gap: f32,
|
||||||
|
|
||||||
/// Used later depending on close behavior
|
|
||||||
widget_clicked_elsewhere: bool,
|
|
||||||
|
|
||||||
/// Default width passed to the Area
|
/// Default width passed to the Area
|
||||||
width: Option<f32>,
|
width: Option<f32>,
|
||||||
sense: Sense,
|
sense: Sense,
|
||||||
|
|
@ -205,7 +202,6 @@ impl<'a> Popup<'a> {
|
||||||
rect_align: RectAlign::BOTTOM_START,
|
rect_align: RectAlign::BOTTOM_START,
|
||||||
alternative_aligns: None,
|
alternative_aligns: None,
|
||||||
gap: 0.0,
|
gap: 0.0,
|
||||||
widget_clicked_elsewhere: false,
|
|
||||||
width: None,
|
width: None,
|
||||||
sense: Sense::click(),
|
sense: Sense::click(),
|
||||||
layout: Layout::default(),
|
layout: Layout::default(),
|
||||||
|
|
@ -219,14 +215,12 @@ impl<'a> Popup<'a> {
|
||||||
///
|
///
|
||||||
/// See [`Self::menu`] and [`Self::context_menu`] for common use cases.
|
/// See [`Self::menu`] and [`Self::context_menu`] for common use cases.
|
||||||
pub fn from_response(response: &Response) -> Self {
|
pub fn from_response(response: &Response) -> Self {
|
||||||
let mut popup = Self::new(
|
Self::new(
|
||||||
Self::default_response_id(response),
|
Self::default_response_id(response),
|
||||||
response.ctx.clone(),
|
response.ctx.clone(),
|
||||||
response,
|
response,
|
||||||
response.layer_id,
|
response.layer_id,
|
||||||
);
|
)
|
||||||
popup.widget_clicked_elsewhere = response.clicked_elsewhere();
|
|
||||||
popup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Show a popup relative to some widget,
|
/// 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
|
/// Returns `None` if the popup is not open or anchor is `PopupAnchor::Pointer` and there is
|
||||||
/// no pointer.
|
/// no pointer.
|
||||||
pub fn show<R>(self, content: impl FnOnce(&mut Ui) -> R) -> Option<InnerResponse<R>> {
|
pub fn show<R>(self, content: impl FnOnce(&mut Ui) -> R) -> Option<InnerResponse<R>> {
|
||||||
let hover_pos = self.ctx.pointer_hover_pos();
|
|
||||||
|
|
||||||
let id = self.id;
|
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 {
|
if let OpenKind::Memory { set } = self.open_kind {
|
||||||
match set {
|
match set {
|
||||||
Some(SetOpenCommand::Bool(open)) => {
|
Some(SetOpenCommand::Bool(open)) => {
|
||||||
|
|
@ -548,7 +547,6 @@ impl<'a> Popup<'a> {
|
||||||
rect_align: _,
|
rect_align: _,
|
||||||
alternative_aligns: _,
|
alternative_aligns: _,
|
||||||
gap,
|
gap,
|
||||||
widget_clicked_elsewhere,
|
|
||||||
width,
|
width,
|
||||||
sense,
|
sense,
|
||||||
layout,
|
layout,
|
||||||
|
|
@ -595,10 +593,13 @@ impl<'a> Popup<'a> {
|
||||||
frame.show(ui, content).inner
|
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 {
|
let closed_by_click = match close_behavior {
|
||||||
PopupCloseBehavior::CloseOnClick => widget_clicked_elsewhere,
|
PopupCloseBehavior::CloseOnClick => close_click,
|
||||||
PopupCloseBehavior::CloseOnClickOutside => {
|
PopupCloseBehavior::CloseOnClickOutside => {
|
||||||
widget_clicked_elsewhere && response.response.clicked_elsewhere()
|
close_click && response.response.clicked_elsewhere()
|
||||||
}
|
}
|
||||||
PopupCloseBehavior::IgnoreClicks => false,
|
PopupCloseBehavior::IgnoreClicks => false,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use crate::rust_view_ui;
|
||||||
use egui::color_picker::{Alpha, color_picker_color32};
|
use egui::color_picker::{Alpha, color_picker_color32};
|
||||||
use egui::containers::menu::{MenuConfig, SubMenuButton};
|
use egui::containers::menu::{MenuConfig, SubMenuButton};
|
||||||
use egui::{
|
use egui::{
|
||||||
Align, Align2, ComboBox, Frame, Id, Layout, Popup, PopupCloseBehavior, RectAlign, RichText,
|
Align, Align2, Atom, Button, ComboBox, Frame, Id, Layout, Popup, PopupCloseBehavior, RectAlign,
|
||||||
Tooltip, Ui, UiBuilder, include_image,
|
RichText, Tooltip, Ui, UiBuilder, include_image,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Showcase [`Popup`].
|
/// Showcase [`Popup`].
|
||||||
|
|
@ -79,13 +79,15 @@ impl PopupsDemo {
|
||||||
} else {
|
} else {
|
||||||
egui::Color32::WHITE
|
egui::Color32::WHITE
|
||||||
};
|
};
|
||||||
let mut color_button =
|
|
||||||
SubMenuButton::new(RichText::new("Background").color(text_color));
|
let button = Button::new((
|
||||||
color_button.button = color_button.button.fill(self.color);
|
RichText::new("Background").color(text_color),
|
||||||
color_button.button = color_button
|
Atom::grow(),
|
||||||
.button
|
RichText::new(SubMenuButton::RIGHT_ARROW).color(text_color),
|
||||||
.right_text(RichText::new(SubMenuButton::RIGHT_ARROW).color(text_color));
|
))
|
||||||
color_button.ui(ui, |ui| {
|
.fill(self.color);
|
||||||
|
|
||||||
|
SubMenuButton::from_button(button).ui(ui, |ui| {
|
||||||
ui.spacing_mut().slider_width = 200.0;
|
ui.spacing_mut().slider_width = 200.0;
|
||||||
color_picker_color32(ui, &mut self.color, Alpha::Opaque);
|
color_picker_color32(ui, &mut self.color, Alpha::Opaque);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue