diff --git a/CHANGELOG.md b/CHANGELOG.md index 2554952e..8894fe7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +### Added ⭐ + +* `egui::popup::popup_below_widget`: show a popup area below another widget + ## 0.8.0 - 2021-01-17 - Grid layout & new visual style diff --git a/egui/src/containers/combo_box.rs b/egui/src/containers/combo_box.rs index a4222c89..a22eaffd 100644 --- a/egui/src/containers/combo_box.rs +++ b/egui/src/containers/combo_box.rs @@ -54,8 +54,6 @@ pub fn combo_box( selected: impl Into, menu_contents: impl FnOnce(&mut Ui), ) -> Response { - const MAX_COMBO_HEIGHT: f32 = 128.0; - let popup_id = button_id.with("popup"); let button_active = ui.memory().is_popup_open(popup_id); @@ -85,33 +83,14 @@ pub fn combo_box( ui.painter() .galley(text_rect.min, galley, text_style, visuals.text_color()); }); + if button_response.clicked { ui.memory().toggle_popup(popup_id); } - - if ui.memory().is_popup_open(popup_id) { - let parent_clip_rect = ui.clip_rect(); - - Area::new(popup_id) - .order(Order::Foreground) - .fixed_pos(button_response.rect.left_bottom()) - .show(ui.ctx(), |ui| { - ui.set_clip_rect(parent_clip_rect); // for when the combo-box is in a scroll area. - let frame = Frame::popup(ui.style()); - let frame_margin = frame.margin; - frame.show(ui, |ui| { - ui.with_layout(Layout::top_down_justified(Align::left()), |ui| { - ui.set_width(button_response.rect.width() - 2.0 * frame_margin.x); - ScrollArea::from_max_height(MAX_COMBO_HEIGHT).show(ui, menu_contents); - }); - }); - }); - - if ui.input().key_pressed(Key::Escape) || ui.input().mouse.click && !button_response.clicked - { - ui.memory().close_popup(); - } - } + const MAX_COMBO_HEIGHT: f32 = 128.0; + crate::popup::popup_below_widget(ui, popup_id, &button_response, |ui| { + ScrollArea::from_max_height(MAX_COMBO_HEIGHT).show(ui, menu_contents) + }); button_response } diff --git a/egui/src/containers/mod.rs b/egui/src/containers/mod.rs index d287a6a8..7d7af7a7 100644 --- a/egui/src/containers/mod.rs +++ b/egui/src/containers/mod.rs @@ -7,7 +7,7 @@ pub(crate) mod collapsing_header; mod combo_box; pub(crate) mod frame; pub(crate) mod panel; -pub(crate) mod popup; +pub mod popup; pub(crate) mod resize; pub(crate) mod scroll_area; pub(crate) mod window; diff --git a/egui/src/containers/popup.rs b/egui/src/containers/popup.rs index 605bf5f0..e2c690b4 100644 --- a/egui/src/containers/popup.rs +++ b/egui/src/containers/popup.rs @@ -1,3 +1,5 @@ +//! Show popup windows, tooltips, context menus etc. + use crate::*; /// Show a tooltip at the current mouse position (if any). @@ -33,7 +35,7 @@ pub fn show_tooltip(ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui)) { // TODO: default size let id = Id::tooltip(); - let response = show_popup(ctx, id, window_pos, add_contents); + let response = show_tooltip_area(ctx, id, window_pos, add_contents); let tooltip_rect = tooltip_rect.unwrap_or_else(Rect::nothing); ctx.frame_state().tooltip_rect = Some(tooltip_rect.union(response.rect)); @@ -58,7 +60,7 @@ pub fn show_tooltip_text(ctx: &CtxRef, text: impl Into) { } /// Show a pop-over window. -fn show_popup( +fn show_tooltip_area( ctx: &CtxRef, id: Id, window_pos: Pos2, @@ -76,3 +78,52 @@ fn show_popup( }) }) } + +/// Shows a popup below another widget. +/// +/// Useful for drop-down menus (combo boxes) or suggestion menus under text fields. +/// +/// You must open the popup with [`Memory::open_popup`] or [`Memory::toggle_popup`]. +/// +/// ``` +/// # let ui = &mut egui::Ui::__test(); +/// let response = ui.button("Open popup"); +/// let popup_id = ui.make_persistent_id("my_unique_id"); +/// if response.clicked { +/// ui.memory().toggle_popup(popup_id); +/// } +/// egui::popup::popup_below_widget(ui, popup_id, &response, |ui| { +/// ui.label("Some more info, or things you can select:"); +/// ui.label("…"); +/// }); +/// ``` +pub fn popup_below_widget( + ui: &Ui, + popup_id: Id, + widget_response: &Response, + add_contents: impl FnOnce(&mut Ui), +) { + if ui.memory().is_popup_open(popup_id) { + let parent_clip_rect = ui.clip_rect(); + + Area::new(popup_id) + .order(Order::Foreground) + .fixed_pos(widget_response.rect.left_bottom()) + .show(ui.ctx(), |ui| { + ui.set_clip_rect(parent_clip_rect); // for when the combo-box is in a scroll area. + let frame = Frame::popup(ui.style()); + let frame_margin = frame.margin; + frame.show(ui, |ui| { + ui.with_layout(Layout::top_down_justified(Align::left()), |ui| { + ui.set_width(widget_response.rect.width() - 2.0 * frame_margin.x); + add_contents(ui) + }); + }); + }); + + if ui.input().key_pressed(Key::Escape) || ui.input().mouse.click && !widget_response.clicked + { + ui.memory().close_popup(); + } + } +}