1use std::sync::Arc;
2
3use gpui::{Div, RenderOnce};
4
5use crate::prelude::*;
6use crate::{Button, Icon, IconButton, TextColor, ToolDivider, Workspace};
7
8#[derive(Default, PartialEq)]
9pub enum Tool {
10 #[default]
11 ProjectPanel,
12 CollaborationPanel,
13 Terminal,
14 Assistant,
15 Feedback,
16 Diagnostics,
17}
18
19struct ToolGroup {
20 active_index: Option<usize>,
21 tools: Vec<Tool>,
22}
23
24impl Default for ToolGroup {
25 fn default() -> Self {
26 ToolGroup {
27 active_index: None,
28 tools: vec![],
29 }
30 }
31}
32
33#[derive(RenderOnce)]
34#[view = "Workspace"]
35pub struct StatusBar {
36 left_tools: Option<ToolGroup>,
37 right_tools: Option<ToolGroup>,
38 bottom_tools: Option<ToolGroup>,
39}
40
41impl Component<Workspace> for StatusBar {
42 type Rendered = Div<Workspace>;
43
44 fn render(self, view: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Self::Rendered {
45 div()
46 .py_0p5()
47 .px_1()
48 .flex()
49 .items_center()
50 .justify_between()
51 .w_full()
52 .bg(cx.theme().colors().status_bar_background)
53 .child(self.left_tools(view, cx))
54 .child(self.right_tools(view, cx))
55 }
56}
57
58impl StatusBar {
59 pub fn new() -> Self {
60 Self {
61 left_tools: None,
62 right_tools: None,
63 bottom_tools: None,
64 }
65 }
66
67 pub fn left_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
68 self.left_tools = {
69 let mut tools = vec![tool];
70 tools.extend(self.left_tools.take().unwrap_or_default().tools);
71 Some(ToolGroup {
72 active_index,
73 tools,
74 })
75 };
76 self
77 }
78
79 pub fn right_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
80 self.right_tools = {
81 let mut tools = vec![tool];
82 tools.extend(self.left_tools.take().unwrap_or_default().tools);
83 Some(ToolGroup {
84 active_index,
85 tools,
86 })
87 };
88 self
89 }
90
91 pub fn bottom_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
92 self.bottom_tools = {
93 let mut tools = vec![tool];
94 tools.extend(self.left_tools.take().unwrap_or_default().tools);
95 Some(ToolGroup {
96 active_index,
97 tools,
98 })
99 };
100 self
101 }
102
103 fn left_tools(&self, workspace: &mut Workspace, cx: &WindowContext) -> impl Element<Workspace> {
104 div()
105 .flex()
106 .items_center()
107 .gap_1()
108 .child(
109 IconButton::<Workspace>::new("project_panel", Icon::FileTree)
110 .when(workspace.is_project_panel_open(), |this| {
111 this.color(TextColor::Accent)
112 })
113 .on_click(|workspace: &mut Workspace, cx| {
114 workspace.toggle_project_panel(cx);
115 }),
116 )
117 .child(
118 IconButton::<Workspace>::new("collab_panel", Icon::Hash)
119 .when(workspace.is_collab_panel_open(), |this| {
120 this.color(TextColor::Accent)
121 })
122 .on_click(|workspace: &mut Workspace, cx| {
123 workspace.toggle_collab_panel();
124 }),
125 )
126 .child(ToolDivider::new())
127 .child(IconButton::new("diagnostics", Icon::XCircle))
128 }
129
130 fn right_tools(
131 &self,
132 workspace: &mut Workspace,
133 cx: &WindowContext,
134 ) -> impl Element<Workspace> {
135 div()
136 .flex()
137 .items_center()
138 .gap_2()
139 .child(
140 div()
141 .flex()
142 .items_center()
143 .gap_1()
144 .child(Button::new("116:25"))
145 .child(
146 Button::<Workspace>::new("Rust").on_click(Arc::new(|workspace, cx| {
147 workspace.toggle_language_selector(cx);
148 })),
149 ),
150 )
151 .child(ToolDivider::new())
152 .child(
153 div()
154 .flex()
155 .items_center()
156 .gap_1()
157 .child(
158 IconButton::new("copilot", Icon::Copilot)
159 .on_click(|_, _| println!("Copilot clicked.")),
160 )
161 .child(
162 IconButton::new("envelope", Icon::Envelope)
163 .on_click(|_, _| println!("Send Feedback clicked.")),
164 ),
165 )
166 .child(ToolDivider::new())
167 .child(
168 div()
169 .flex()
170 .items_center()
171 .gap_1()
172 .child(
173 IconButton::<Workspace>::new("terminal", Icon::Terminal)
174 .when(workspace.is_terminal_open(), |this| {
175 this.color(TextColor::Accent)
176 })
177 .on_click(|workspace: &mut Workspace, cx| {
178 workspace.toggle_terminal(cx);
179 }),
180 )
181 .child(
182 IconButton::<Workspace>::new("chat_panel", Icon::MessageBubbles)
183 .when(workspace.is_chat_panel_open(), |this| {
184 this.color(TextColor::Accent)
185 })
186 .on_click(|workspace: &mut Workspace, cx| {
187 workspace.toggle_chat_panel(cx);
188 }),
189 )
190 .child(
191 IconButton::<Workspace>::new("assistant_panel", Icon::Ai)
192 .when(workspace.is_assistant_panel_open(), |this| {
193 this.color(TextColor::Accent)
194 })
195 .on_click(|workspace: &mut Workspace, cx| {
196 workspace.toggle_assistant_panel(cx);
197 }),
198 ),
199 )
200 }
201}