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