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}