1use crate::{ItemHandle, Pane};
2use gpui::{
3 elements::*, AnyViewHandle, ElementBox, Entity, MutableAppContext, RenderContext, Subscription,
4 View, ViewContext, ViewHandle,
5};
6use settings::Settings;
7
8pub trait StatusItemView: View {
9 fn set_active_pane_item(
10 &mut self,
11 active_pane_item: Option<&dyn crate::ItemHandle>,
12 cx: &mut ViewContext<Self>,
13 );
14}
15
16trait StatusItemViewHandle {
17 fn to_any(&self) -> AnyViewHandle;
18 fn set_active_pane_item(
19 &self,
20 active_pane_item: Option<&dyn ItemHandle>,
21 cx: &mut MutableAppContext,
22 );
23}
24
25pub struct StatusBar {
26 left_items: Vec<Box<dyn StatusItemViewHandle>>,
27 right_items: Vec<Box<dyn StatusItemViewHandle>>,
28 active_pane: ViewHandle<Pane>,
29 _observe_active_pane: Subscription,
30}
31
32impl Entity for StatusBar {
33 type Event = ();
34}
35
36impl View for StatusBar {
37 fn ui_name() -> &'static str {
38 "StatusBar"
39 }
40
41 fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
42 let theme = &cx.global::<Settings>().theme.workspace.status_bar;
43 Flex::row()
44 .with_children(self.left_items.iter().map(|i| {
45 ChildView::new(i.as_ref(), cx)
46 .aligned()
47 .contained()
48 .with_margin_right(theme.item_spacing)
49 .boxed()
50 }))
51 .with_children(self.right_items.iter().rev().map(|i| {
52 ChildView::new(i.as_ref(), cx)
53 .aligned()
54 .contained()
55 .with_margin_left(theme.item_spacing)
56 .flex_float()
57 .boxed()
58 }))
59 .contained()
60 .with_style(theme.container)
61 .constrained()
62 .with_height(theme.height)
63 .boxed()
64 }
65}
66
67impl StatusBar {
68 pub fn new(active_pane: &ViewHandle<Pane>, cx: &mut ViewContext<Self>) -> Self {
69 let mut this = Self {
70 left_items: Default::default(),
71 right_items: Default::default(),
72 active_pane: active_pane.clone(),
73 _observe_active_pane: cx
74 .observe(active_pane, |this, _, cx| this.update_active_pane_item(cx)),
75 };
76 this.update_active_pane_item(cx);
77 this
78 }
79
80 pub fn add_left_item<T>(&mut self, item: ViewHandle<T>, cx: &mut ViewContext<Self>)
81 where
82 T: 'static + StatusItemView,
83 {
84 cx.reparent(&item);
85 self.left_items.push(Box::new(item));
86 cx.notify();
87 }
88
89 pub fn add_right_item<T>(&mut self, item: ViewHandle<T>, cx: &mut ViewContext<Self>)
90 where
91 T: 'static + StatusItemView,
92 {
93 cx.reparent(&item);
94 self.right_items.push(Box::new(item));
95 cx.notify();
96 }
97
98 pub fn set_active_pane(&mut self, active_pane: &ViewHandle<Pane>, cx: &mut ViewContext<Self>) {
99 self.active_pane = active_pane.clone();
100 self._observe_active_pane =
101 cx.observe(active_pane, |this, _, cx| this.update_active_pane_item(cx));
102 self.update_active_pane_item(cx);
103 }
104
105 fn update_active_pane_item(&mut self, cx: &mut ViewContext<Self>) {
106 let active_pane_item = self.active_pane.read(cx).active_item();
107 for item in self.left_items.iter().chain(&self.right_items) {
108 item.set_active_pane_item(active_pane_item.as_deref(), cx);
109 }
110 }
111}
112
113impl<T: StatusItemView> StatusItemViewHandle for ViewHandle<T> {
114 fn to_any(&self) -> AnyViewHandle {
115 self.into()
116 }
117
118 fn set_active_pane_item(
119 &self,
120 active_pane_item: Option<&dyn ItemHandle>,
121 cx: &mut MutableAppContext,
122 ) {
123 self.update(cx, |this, cx| {
124 this.set_active_pane_item(active_pane_item, cx)
125 });
126 }
127}
128
129impl From<&dyn StatusItemViewHandle> for AnyViewHandle {
130 fn from(val: &dyn StatusItemViewHandle) -> Self {
131 val.to_any()
132 }
133}