model_selector_popover.rs

 1use std::rc::Rc;
 2
 3use acp_thread::AgentModelSelector;
 4use agent_client_protocol as acp;
 5use gpui::{Entity, FocusHandle};
 6use picker::popover_menu::PickerPopoverMenu;
 7use ui::{
 8    ButtonLike, Context, IntoElement, PopoverMenuHandle, SharedString, Tooltip, Window, prelude::*,
 9};
10use zed_actions::agent::ToggleModelSelector;
11
12use crate::acp::{AcpModelSelector, model_selector::acp_model_selector};
13
14pub struct AcpModelSelectorPopover {
15    selector: Entity<AcpModelSelector>,
16    menu_handle: PopoverMenuHandle<AcpModelSelector>,
17    focus_handle: FocusHandle,
18}
19
20impl AcpModelSelectorPopover {
21    pub(crate) fn new(
22        session_id: acp::SessionId,
23        selector: Rc<dyn AgentModelSelector>,
24        menu_handle: PopoverMenuHandle<AcpModelSelector>,
25        focus_handle: FocusHandle,
26        window: &mut Window,
27        cx: &mut Context<Self>,
28    ) -> Self {
29        Self {
30            selector: cx.new(move |cx| acp_model_selector(session_id, selector, window, cx)),
31            menu_handle,
32            focus_handle,
33        }
34    }
35
36    pub fn toggle(&self, window: &mut Window, cx: &mut Context<Self>) {
37        self.menu_handle.toggle(window, cx);
38    }
39
40    pub fn active_model_name(&self, cx: &App) -> Option<SharedString> {
41        self.selector
42            .read(cx)
43            .delegate
44            .active_model()
45            .map(|model| model.name.clone())
46    }
47}
48
49impl Render for AcpModelSelectorPopover {
50    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
51        let model = self.selector.read(cx).delegate.active_model();
52        let model_name = model
53            .as_ref()
54            .map(|model| model.name.clone())
55            .unwrap_or_else(|| SharedString::from("Select a Model"));
56
57        let model_icon = model.as_ref().and_then(|model| model.icon);
58
59        let focus_handle = self.focus_handle.clone();
60
61        PickerPopoverMenu::new(
62            self.selector.clone(),
63            ButtonLike::new("active-model")
64                .when_some(model_icon, |this, icon| {
65                    this.child(Icon::new(icon).color(Color::Muted).size(IconSize::XSmall))
66                })
67                .child(
68                    Label::new(model_name)
69                        .color(Color::Muted)
70                        .size(LabelSize::Small)
71                        .ml_0p5(),
72                )
73                .child(
74                    Icon::new(IconName::ChevronDown)
75                        .color(Color::Muted)
76                        .size(IconSize::XSmall),
77                ),
78            move |window, cx| {
79                Tooltip::for_action_in(
80                    "Change Model",
81                    &ToggleModelSelector,
82                    &focus_handle,
83                    window,
84                    cx,
85                )
86            },
87            gpui::Corner::BottomRight,
88            cx,
89        )
90        .with_handle(self.menu_handle.clone())
91        .render(window, cx)
92    }
93}