egui_components/
popover.rs1use egui::{Frame, Id, InnerResponse, Margin, Response, Ui};
16use egui_components_theme::Theme;
17
18pub struct Popover {
19 id: Id,
20 width: Option<f32>,
21 gap: f32,
22 close_on_click: bool,
23}
24
25impl Popover {
26 pub fn new(id_salt: impl std::hash::Hash) -> Self {
27 Self {
28 id: Id::new(id_salt),
29 width: None,
30 gap: 4.0,
31 close_on_click: false,
32 }
33 }
34 pub fn width(mut self, w: f32) -> Self {
35 self.width = Some(w);
36 self
37 }
38 pub fn gap(mut self, gap: f32) -> Self {
39 self.gap = gap;
40 self
41 }
42 pub fn close_on_click(mut self) -> Self {
45 self.close_on_click = true;
46 self
47 }
48
49 pub fn show<R>(
52 self,
53 ui: &mut Ui,
54 trigger: &Response,
55 content: impl FnOnce(&mut Ui) -> R,
56 ) -> Option<R> {
57 let theme = Theme::get(ui.ctx());
58 let c = theme.colors;
59
60 let frame = Frame::new()
61 .fill(c.popover_background)
62 .stroke(theme.border_stroke())
63 .corner_radius(theme.corner())
64 .inner_margin(Margin::same(12))
65 .shadow(egui::epaint::Shadow {
66 offset: [0, 4],
67 blur: 16,
68 spread: 0,
69 color: c.overlay,
70 });
71
72 let close = if self.close_on_click {
73 egui::PopupCloseBehavior::CloseOnClick
74 } else {
75 egui::PopupCloseBehavior::CloseOnClickOutside
76 };
77
78 let mut popup = egui::Popup::from_toggle_button_response(trigger)
79 .id(ui.make_persistent_id(self.id).with("popup"))
80 .gap(self.gap)
81 .close_behavior(close)
82 .frame(frame);
83 if let Some(w) = self.width {
84 popup = popup.width(w);
85 }
86
87 popup
88 .show(|ui| {
89 if let Some(w) = self.width {
90 ui.set_width(w - 24.0);
91 }
92 content(ui)
93 })
94 .map(|r: InnerResponse<R>| r.inner)
95 }
96}