1use gpui::{
2 AnyView, Corner, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Pixels, Point,
3 Subscription,
4};
5use ui::{
6 FluentBuilder as _, IntoElement, PopoverMenu, PopoverMenuHandle, PopoverTrigger, prelude::*,
7};
8
9use crate::{Picker, PickerDelegate};
10
11pub struct PickerPopoverMenu<T, TT, P>
12where
13 T: PopoverTrigger + ButtonCommon,
14 TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
15 P: PickerDelegate,
16{
17 picker: Entity<Picker<P>>,
18 trigger: T,
19 tooltip: TT,
20 handle: Option<PopoverMenuHandle<Picker<P>>>,
21 anchor: Corner,
22 offset: Option<Point<Pixels>>,
23 _subscriptions: Vec<Subscription>,
24}
25
26impl<T, TT, P> PickerPopoverMenu<T, TT, P>
27where
28 T: PopoverTrigger + ButtonCommon,
29 TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
30 P: PickerDelegate,
31{
32 pub fn new(
33 picker: Entity<Picker<P>>,
34 trigger: T,
35 tooltip: TT,
36 anchor: Corner,
37 cx: &mut App,
38 ) -> Self {
39 Self {
40 _subscriptions: vec![cx.subscribe(&picker, |picker, &DismissEvent, cx| {
41 picker.update(cx, |_, cx| cx.emit(DismissEvent));
42 })],
43 picker,
44 trigger,
45 tooltip,
46 handle: None,
47 offset: Some(Point {
48 x: px(0.0),
49 y: px(-2.0),
50 }),
51 anchor,
52 }
53 }
54
55 pub fn with_handle(mut self, handle: PopoverMenuHandle<Picker<P>>) -> Self {
56 self.handle = Some(handle);
57 self
58 }
59
60 pub fn offset(mut self, offset: Point<Pixels>) -> Self {
61 self.offset = Some(offset);
62 self
63 }
64}
65
66impl<T, TT, P> EventEmitter<DismissEvent> for PickerPopoverMenu<T, TT, P>
67where
68 T: PopoverTrigger + ButtonCommon,
69 TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
70 P: PickerDelegate,
71{
72}
73
74impl<T, TT, P> Focusable for PickerPopoverMenu<T, TT, P>
75where
76 T: PopoverTrigger + ButtonCommon,
77 TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
78 P: PickerDelegate,
79{
80 fn focus_handle(&self, cx: &App) -> FocusHandle {
81 self.picker.focus_handle(cx)
82 }
83}
84
85impl<T, TT, P> RenderOnce for PickerPopoverMenu<T, TT, P>
86where
87 T: PopoverTrigger + ButtonCommon,
88 TT: Fn(&mut Window, &mut App) -> AnyView + 'static,
89 P: PickerDelegate,
90{
91 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
92 let picker = self.picker.clone();
93
94 PopoverMenu::new("popover-menu")
95 .menu(move |_window, _cx| Some(picker.clone()))
96 .trigger_with_tooltip(self.trigger, self.tooltip)
97 .anchor(self.anchor)
98 .when_some(self.handle, |menu, handle| menu.with_handle(handle))
99 .when_some(self.offset, |menu, offset| menu.offset(offset))
100 }
101}