popover_button.rs

 1use gpui::{AnyView, Corner, Entity, ManagedView};
 2use ui::{
 3    px, App, ButtonCommon, IntoElement, PopoverMenu, PopoverMenuHandle, PopoverTrigger, RenderOnce,
 4    Window,
 5};
 6
 7pub trait TriggerablePopover: ManagedView {
 8    fn menu_handle(
 9        &mut self,
10        window: &mut Window,
11        cx: &mut gpui::Context<Self>,
12    ) -> PopoverMenuHandle<Self>;
13}
14
15// We want a button, that tells us what parameters to pass, and that "just works" after that
16pub struct PopoverButton<T, B, F> {
17    selector: Entity<T>,
18    button: B,
19    tooltip: F,
20    corner: Corner,
21}
22
23impl<T, B, F> PopoverButton<T, B, F> {
24    pub fn new(selector: Entity<T>, corner: Corner, button: B, tooltip: F) -> Self
25    where
26        F: Fn(&mut Window, &mut App) -> AnyView + 'static,
27    {
28        Self {
29            selector,
30            button,
31            tooltip,
32            corner,
33        }
34    }
35}
36
37impl<T: TriggerablePopover, B: PopoverTrigger + ButtonCommon, F> RenderOnce
38    for PopoverButton<T, B, F>
39where
40    F: Fn(&mut Window, &mut App) -> AnyView + 'static,
41{
42    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
43        let menu_handle = self
44            .selector
45            .update(cx, |selector, cx| selector.menu_handle(window, cx));
46
47        PopoverMenu::new("popover-button")
48            .menu({
49                let selector = self.selector.clone();
50                move |_window, _cx| Some(selector.clone())
51            })
52            .trigger_with_tooltip(self.button, self.tooltip)
53            .anchor(self.corner)
54            .with_handle(menu_handle)
55            .offset(gpui::Point {
56                x: px(0.0),
57                y: px(-2.0),
58            })
59    }
60}