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}