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}