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