Browse Source

add popup_below_widget to show a popup area below another widget

Closes https://github.com/emilk/egui/issues/122
pull/135/head
Emil Ernerfeldt 4 years ago
parent
commit
3bec7c4f68
  1. 4
      CHANGELOG.md
  2. 31
      egui/src/containers/combo_box.rs
  3. 2
      egui/src/containers/mod.rs
  4. 55
      egui/src/containers/popup.rs

4
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

31
egui/src/containers/combo_box.rs

@ -54,8 +54,6 @@ pub fn combo_box(
selected: impl Into<String>,
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
}

2
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;

55
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<String>) {
}
/// 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();
}
}
}

Loading…
Cancel
Save