status_bar.rs

  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}