Skip to main content

ui/components/ai/
agent_setup_button.rs

1use crate::prelude::*;
2use gpui::{ClickEvent, SharedString};
3
4#[derive(IntoElement, RegisterComponent)]
5pub struct AgentSetupButton {
6    id: ElementId,
7    icon: Option<Icon>,
8    name: Option<SharedString>,
9    state: Option<AnyElement>,
10    disabled: bool,
11    on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
12}
13
14impl AgentSetupButton {
15    pub fn new(id: impl Into<ElementId>) -> Self {
16        Self {
17            id: id.into(),
18            icon: None,
19            name: None,
20            state: None,
21            disabled: false,
22            on_click: None,
23        }
24    }
25
26    pub fn icon(mut self, icon: Icon) -> Self {
27        self.icon = Some(icon);
28        self
29    }
30
31    pub fn name(mut self, name: impl Into<SharedString>) -> Self {
32        self.name = Some(name.into());
33        self
34    }
35
36    pub fn state(mut self, element: impl IntoElement) -> Self {
37        self.state = Some(element.into_any_element());
38        self
39    }
40
41    pub fn disabled(mut self, disabled: bool) -> Self {
42        self.disabled = disabled;
43        self
44    }
45
46    pub fn on_click(
47        mut self,
48        handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
49    ) -> Self {
50        self.on_click = Some(Box::new(handler));
51        self
52    }
53}
54
55impl Component for AgentSetupButton {
56    fn scope() -> ComponentScope {
57        ComponentScope::Agent
58    }
59
60    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
61        None
62    }
63}
64
65impl RenderOnce for AgentSetupButton {
66    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
67        let is_clickable = !self.disabled && self.on_click.is_some();
68
69        let has_top_section = self.icon.is_some() || self.name.is_some();
70        let top_section = has_top_section.then(|| {
71            h_flex()
72                .p_1p5()
73                .gap_1()
74                .justify_center()
75                .when_some(self.icon, |this, icon| this.child(icon))
76                .when_some(self.name, |this, name| {
77                    this.child(Label::new(name).size(LabelSize::Small))
78                })
79        });
80
81        let bottom_section = self.state.map(|state_element| {
82            h_flex()
83                .p_0p5()
84                .h_full()
85                .justify_center()
86                .border_t_1()
87                .border_color(cx.theme().colors().border_variant)
88                .bg(cx.theme().colors().element_background.opacity(0.5))
89                .child(state_element)
90        });
91
92        v_flex()
93            .id(self.id)
94            .border_1()
95            .border_color(cx.theme().colors().border_variant)
96            .rounded_sm()
97            .when(is_clickable, |this| {
98                this.cursor_pointer().hover(|style| {
99                    style
100                        .bg(cx.theme().colors().element_hover)
101                        .border_color(cx.theme().colors().border)
102                })
103            })
104            .when_some(top_section, |this, section| this.child(section))
105            .when_some(bottom_section, |this, section| this.child(section))
106            .when_some(self.on_click.filter(|_| is_clickable), |this, on_click| {
107                this.on_click(on_click)
108            })
109    }
110}