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