status_bar.rs

  1use std::marker::PhantomData;
  2use std::sync::atomic::Ordering;
  3use std::sync::Arc;
  4
  5use crate::prelude::*;
  6use crate::{get_workspace_state, Button, Icon, IconButton, IconColor, ToolDivider};
  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(Element)]
 34pub struct StatusBar<S: 'static + Send + Sync + Clone> {
 35    state_type: PhantomData<S>,
 36    left_tools: Option<ToolGroup>,
 37    right_tools: Option<ToolGroup>,
 38    bottom_tools: Option<ToolGroup>,
 39}
 40
 41impl<S: 'static + Send + Sync + Clone> StatusBar<S> {
 42    pub fn new() -> Self {
 43        Self {
 44            state_type: PhantomData,
 45            left_tools: None,
 46            right_tools: None,
 47            bottom_tools: None,
 48        }
 49    }
 50
 51    pub fn left_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
 52        self.left_tools = {
 53            let mut tools = vec![tool];
 54            tools.extend(self.left_tools.take().unwrap_or_default().tools);
 55            Some(ToolGroup {
 56                active_index,
 57                tools,
 58            })
 59        };
 60        self
 61    }
 62
 63    pub fn right_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
 64        self.right_tools = {
 65            let mut tools = vec![tool];
 66            tools.extend(self.left_tools.take().unwrap_or_default().tools);
 67            Some(ToolGroup {
 68                active_index,
 69                tools,
 70            })
 71        };
 72        self
 73    }
 74
 75    pub fn bottom_tool(mut self, tool: Tool, active_index: Option<usize>) -> Self {
 76        self.bottom_tools = {
 77            let mut tools = vec![tool];
 78            tools.extend(self.left_tools.take().unwrap_or_default().tools);
 79            Some(ToolGroup {
 80                active_index,
 81                tools,
 82            })
 83        };
 84        self
 85    }
 86
 87    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
 88        let theme = theme(cx);
 89
 90        div()
 91            .py_0p5()
 92            .px_1()
 93            .flex()
 94            .items_center()
 95            .justify_between()
 96            .w_full()
 97            .fill(theme.lowest.base.default.background)
 98            .child(self.left_tools(&theme))
 99            .child(self.right_tools(&theme))
100    }
101
102    fn left_tools(&self, theme: &Theme) -> impl Element<State = S> {
103        let workspace_state = get_workspace_state();
104
105        div()
106            .flex()
107            .items_center()
108            .gap_1()
109            .child(
110                IconButton::new(Icon::FileTree)
111                    .when(
112                        workspace_state.show_project_panel.load(Ordering::SeqCst),
113                        |this| this.color(IconColor::Accent),
114                    )
115                    .on_click(|_, cx| {
116                        let is_showing_project_panel =
117                            workspace_state.show_project_panel.load(Ordering::SeqCst);
118
119                        workspace_state
120                            .show_project_panel
121                            .compare_exchange(
122                                is_showing_project_panel,
123                                !is_showing_project_panel,
124                                Ordering::SeqCst,
125                                Ordering::SeqCst,
126                            )
127                            .unwrap();
128
129                        cx.notify();
130                    }),
131            )
132            .child(IconButton::new(Icon::Hash))
133            .child(ToolDivider::new())
134            .child(IconButton::new(Icon::XCircle))
135    }
136
137    fn right_tools(&self, theme: &Theme) -> impl Element<State = S> {
138        let workspace_state = get_workspace_state();
139
140        div()
141            .flex()
142            .items_center()
143            .gap_2()
144            .child(
145                div()
146                    .flex()
147                    .items_center()
148                    .gap_1()
149                    .child(Button::new("116:25"))
150                    .child(Button::new("Rust").on_click(Arc::new(|_, cx| {
151                        let is_showing_language_selector = workspace_state
152                            .show_language_selector
153                            .load(Ordering::SeqCst);
154
155                        workspace_state
156                            .show_language_selector
157                            .compare_exchange(
158                                is_showing_language_selector,
159                                !is_showing_language_selector,
160                                Ordering::SeqCst,
161                                Ordering::SeqCst,
162                            )
163                            .unwrap();
164
165                        cx.notify();
166                    }))),
167            )
168            .child(ToolDivider::new())
169            .child(
170                div()
171                    .flex()
172                    .items_center()
173                    .gap_1()
174                    .child(
175                        IconButton::new(Icon::Copilot)
176                            .on_click(|_, _| println!("Copilot clicked.")),
177                    )
178                    .child(
179                        IconButton::new(Icon::Envelope)
180                            .on_click(|_, _| println!("Send Feedback clicked.")),
181                    ),
182            )
183            .child(ToolDivider::new())
184            .child(
185                div()
186                    .flex()
187                    .items_center()
188                    .gap_1()
189                    .child(
190                        IconButton::new(Icon::Terminal)
191                            .when(
192                                workspace_state.show_terminal.load(Ordering::SeqCst),
193                                |this| this.color(IconColor::Accent),
194                            )
195                            .on_click(|_, cx| {
196                                let is_showing_terminal =
197                                    workspace_state.show_terminal.load(Ordering::SeqCst);
198
199                                workspace_state
200                                    .show_terminal
201                                    .compare_exchange(
202                                        is_showing_terminal,
203                                        !is_showing_terminal,
204                                        Ordering::SeqCst,
205                                        Ordering::SeqCst,
206                                    )
207                                    .unwrap();
208
209                                cx.notify();
210                            }),
211                    )
212                    .child(
213                        IconButton::new(Icon::MessageBubbles)
214                            .when(
215                                workspace_state.show_chat_panel.load(Ordering::SeqCst),
216                                |this| this.color(IconColor::Accent),
217                            )
218                            .on_click(|_, cx| {
219                                let is_showing_chat_panel =
220                                    workspace_state.show_chat_panel.load(Ordering::SeqCst);
221
222                                workspace_state
223                                    .show_chat_panel
224                                    .compare_exchange(
225                                        is_showing_chat_panel,
226                                        !is_showing_chat_panel,
227                                        Ordering::SeqCst,
228                                        Ordering::SeqCst,
229                                    )
230                                    .unwrap();
231
232                                cx.notify();
233                            }),
234                    )
235                    .child(IconButton::new(Icon::Ai)),
236            )
237    }
238}