1use std::sync::Arc;
2
3use chrono::DateTime;
4use gpui2::{px, relative, Div, Render, Size, View, VisualContext};
5use settings2::Settings;
6use theme2::ThemeSettings;
7
8use crate::prelude::*;
9use crate::{
10 static_livestream, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, CollabPanel,
11 EditorPane, Label, LanguageSelector, NotificationsPanel, Pane, PaneGroup, Panel,
12 PanelAllowedSides, PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar,
13 Toast, ToastOrigin,
14};
15
16#[derive(Clone)]
17pub struct Gpui2UiDebug {
18 pub in_livestream: bool,
19 pub enable_user_settings: bool,
20 pub show_toast: bool,
21}
22
23impl Default for Gpui2UiDebug {
24 fn default() -> Self {
25 Self {
26 in_livestream: false,
27 enable_user_settings: false,
28 show_toast: false,
29 }
30 }
31}
32
33#[derive(Clone)]
34pub struct Workspace {
35 title_bar: View<TitleBar>,
36 editor_1: View<EditorPane>,
37 show_project_panel: bool,
38 show_collab_panel: bool,
39 show_chat_panel: bool,
40 show_assistant_panel: bool,
41 show_notifications_panel: bool,
42 show_terminal: bool,
43 show_debug: bool,
44 show_language_selector: bool,
45 debug: Gpui2UiDebug,
46}
47
48impl Workspace {
49 pub fn new(cx: &mut ViewContext<Self>) -> Self {
50 Self {
51 title_bar: TitleBar::view(cx, None),
52 editor_1: EditorPane::view(cx),
53 show_project_panel: true,
54 show_collab_panel: false,
55 show_chat_panel: false,
56 show_assistant_panel: false,
57 show_terminal: true,
58 show_language_selector: false,
59 show_debug: false,
60 show_notifications_panel: true,
61 debug: Gpui2UiDebug::default(),
62 }
63 }
64
65 pub fn is_project_panel_open(&self) -> bool {
66 self.show_project_panel
67 }
68
69 pub fn toggle_project_panel(&mut self, cx: &mut ViewContext<Self>) {
70 self.show_project_panel = !self.show_project_panel;
71
72 self.show_collab_panel = false;
73
74 cx.notify();
75 }
76
77 pub fn is_collab_panel_open(&self) -> bool {
78 self.show_collab_panel
79 }
80
81 pub fn toggle_collab_panel(&mut self) {
82 self.show_collab_panel = !self.show_collab_panel;
83
84 self.show_project_panel = false;
85 }
86
87 pub fn is_terminal_open(&self) -> bool {
88 self.show_terminal
89 }
90
91 pub fn toggle_terminal(&mut self, cx: &mut ViewContext<Self>) {
92 self.show_terminal = !self.show_terminal;
93
94 cx.notify();
95 }
96
97 pub fn is_chat_panel_open(&self) -> bool {
98 self.show_chat_panel
99 }
100
101 pub fn toggle_chat_panel(&mut self, cx: &mut ViewContext<Self>) {
102 self.show_chat_panel = !self.show_chat_panel;
103
104 self.show_assistant_panel = false;
105 self.show_notifications_panel = false;
106
107 cx.notify();
108 }
109
110 pub fn is_notifications_panel_open(&self) -> bool {
111 self.show_notifications_panel
112 }
113
114 pub fn toggle_notifications_panel(&mut self, cx: &mut ViewContext<Self>) {
115 self.show_notifications_panel = !self.show_notifications_panel;
116
117 self.show_chat_panel = false;
118 self.show_assistant_panel = false;
119
120 cx.notify();
121 }
122
123 pub fn is_assistant_panel_open(&self) -> bool {
124 self.show_assistant_panel
125 }
126
127 pub fn toggle_assistant_panel(&mut self, cx: &mut ViewContext<Self>) {
128 self.show_assistant_panel = !self.show_assistant_panel;
129
130 self.show_chat_panel = false;
131 self.show_notifications_panel = false;
132
133 cx.notify();
134 }
135
136 pub fn is_language_selector_open(&self) -> bool {
137 self.show_language_selector
138 }
139
140 pub fn toggle_language_selector(&mut self, cx: &mut ViewContext<Self>) {
141 self.show_language_selector = !self.show_language_selector;
142
143 cx.notify();
144 }
145
146 pub fn toggle_debug(&mut self, cx: &mut ViewContext<Self>) {
147 self.show_debug = !self.show_debug;
148
149 cx.notify();
150 }
151
152 pub fn debug_toggle_user_settings(&mut self, cx: &mut ViewContext<Self>) {
153 self.debug.enable_user_settings = !self.debug.enable_user_settings;
154
155 let mut theme_settings = ThemeSettings::get_global(cx).clone();
156
157 if self.debug.enable_user_settings {
158 theme_settings.ui_font_size = 18.0.into();
159 } else {
160 theme_settings.ui_font_size = 16.0.into();
161 }
162
163 ThemeSettings::override_global(theme_settings.clone(), cx);
164
165 cx.set_rem_size(theme_settings.ui_font_size);
166
167 cx.notify();
168 }
169
170 pub fn debug_toggle_livestream(&mut self, cx: &mut ViewContext<Self>) {
171 self.debug.in_livestream = !self.debug.in_livestream;
172
173 self.title_bar = TitleBar::view(
174 cx,
175 Some(static_livestream()).filter(|_| self.debug.in_livestream),
176 );
177
178 cx.notify();
179 }
180
181 pub fn debug_toggle_toast(&mut self, cx: &mut ViewContext<Self>) {
182 self.debug.show_toast = !self.debug.show_toast;
183
184 cx.notify();
185 }
186
187 pub fn view(cx: &mut WindowContext) -> View<Self> {
188 cx.build_view(|cx| Self::new(cx))
189 }
190}
191
192impl Render for Workspace {
193 type Element = Div<Self>;
194
195 fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
196 let root_group = PaneGroup::new_panes(
197 vec![Pane::new(
198 "pane-0",
199 Size {
200 width: relative(1.).into(),
201 height: relative(1.).into(),
202 },
203 )
204 .child(self.editor_1.clone())],
205 SplitDirection::Horizontal,
206 );
207
208 div()
209 .relative()
210 .size_full()
211 .flex()
212 .flex_col()
213 .font("Zed Sans")
214 .gap_0()
215 .justify_start()
216 .items_start()
217 .text_color(cx.theme().colors().text)
218 .bg(cx.theme().colors().background)
219 .child(self.title_bar.clone())
220 .child(
221 div()
222 .flex_1()
223 .w_full()
224 .flex()
225 .flex_row()
226 .overflow_hidden()
227 .border_t()
228 .border_b()
229 .border_color(cx.theme().colors().border)
230 .children(
231 Some(
232 Panel::new("project-panel-outer", cx)
233 .side(PanelSide::Left)
234 .child(ProjectPanel::new("project-panel-inner")),
235 )
236 .filter(|_| self.is_project_panel_open()),
237 )
238 .children(
239 Some(
240 Panel::new("collab-panel-outer", cx)
241 .child(CollabPanel::new("collab-panel-inner"))
242 .side(PanelSide::Left),
243 )
244 .filter(|_| self.is_collab_panel_open()),
245 )
246 // .child(NotificationToast::new(
247 // "maxbrunsfeld has requested to add you as a contact.".into(),
248 // ))
249 .child(
250 v_stack()
251 .flex_1()
252 .h_full()
253 .child(div().flex().flex_1().child(root_group))
254 .children(
255 Some(
256 Panel::new("terminal-panel", cx)
257 .child(Terminal::new())
258 .allowed_sides(PanelAllowedSides::BottomOnly)
259 .side(PanelSide::Bottom),
260 )
261 .filter(|_| self.is_terminal_open()),
262 ),
263 )
264 .children(
265 Some(
266 Panel::new("chat-panel-outer", cx)
267 .side(PanelSide::Right)
268 .child(ChatPanel::new("chat-panel-inner").messages(vec![
269 ChatMessage::new(
270 "osiewicz".to_string(),
271 "is this thing on?".to_string(),
272 DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
273 .unwrap()
274 .naive_local(),
275 ),
276 ChatMessage::new(
277 "maxdeviant".to_string(),
278 "Reading you loud and clear!".to_string(),
279 DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
280 .unwrap()
281 .naive_local(),
282 ),
283 ])),
284 )
285 .filter(|_| self.is_chat_panel_open()),
286 )
287 .children(
288 Some(
289 Panel::new("notifications-panel-outer", cx)
290 .side(PanelSide::Right)
291 .child(NotificationsPanel::new("notifications-panel-inner")),
292 )
293 .filter(|_| self.is_notifications_panel_open()),
294 )
295 .children(
296 Some(
297 Panel::new("assistant-panel-outer", cx)
298 .child(AssistantPanel::new("assistant-panel-inner")),
299 )
300 .filter(|_| self.is_assistant_panel_open()),
301 ),
302 )
303 .child(StatusBar::new())
304 .when(self.debug.show_toast, |this| {
305 this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast")))
306 })
307 .children(
308 Some(
309 div()
310 .absolute()
311 .top(px(50.))
312 .left(px(640.))
313 .z_index(8)
314 .child(LanguageSelector::new("language-selector")),
315 )
316 .filter(|_| self.is_language_selector_open()),
317 )
318 .z_index(8)
319 // Debug
320 .child(
321 v_stack()
322 .z_index(9)
323 .absolute()
324 .top_20()
325 .left_1_4()
326 .w_40()
327 .gap_2()
328 .when(self.show_debug, |this| {
329 this.child(Button::<Workspace>::new("Toggle User Settings").on_click(
330 Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)),
331 ))
332 .child(
333 Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new(
334 |workspace, cx| workspace.debug_toggle_toast(cx),
335 )),
336 )
337 .child(
338 Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new(
339 |workspace, cx| workspace.debug_toggle_livestream(cx),
340 )),
341 )
342 })
343 .child(
344 Button::<Workspace>::new("Toggle Debug")
345 .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
346 ),
347 )
348 }
349}
350
351#[cfg(feature = "stories")]
352pub use stories::*;
353
354#[cfg(feature = "stories")]
355mod stories {
356 use super::*;
357 use gpui2::VisualContext;
358
359 pub struct WorkspaceStory {
360 workspace: View<Workspace>,
361 }
362
363 impl WorkspaceStory {
364 pub fn view(cx: &mut WindowContext) -> View<Self> {
365 cx.build_view(|cx| Self {
366 workspace: Workspace::view(cx),
367 })
368 }
369 }
370
371 impl Render for WorkspaceStory {
372 type Element = Div<Self>;
373
374 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
375 div().child(self.workspace.clone())
376 }
377 }
378}