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(
46 self.left_items
47 .iter()
48 .map(|i| ChildView::new(i.as_ref()).aligned().boxed()),
49 )
50 .with_child(Empty::new().flexible(1., true).boxed())
51 .with_children(
52 self.right_items
53 .iter()
54 .map(|i| ChildView::new(i.as_ref()).aligned().boxed()),
55 )
56 .contained()
57 .with_style(theme.container)
58 .constrained()
59 .with_height(theme.height)
60 .boxed()
61 }
62}
63
64impl StatusBar {
65 pub fn new(
66 active_pane: &ViewHandle<Pane>,
67 settings: watch::Receiver<Settings>,
68 cx: &mut ViewContext<Self>,
69 ) -> Self {
70 let mut this = Self {
71 left_items: Default::default(),
72 right_items: Default::default(),
73 active_pane: active_pane.clone(),
74 _observe_active_pane: cx
75 .observe(active_pane, |this, _, cx| this.update_active_pane_item(cx)),
76 settings,
77 };
78 this.update_active_pane_item(cx);
79 this
80 }
81
82 pub fn add_left_item<T>(&mut self, item: ViewHandle<T>, cx: &mut ViewContext<Self>)
83 where
84 T: 'static + StatusItemView,
85 {
86 self.left_items.push(Box::new(item));
87 cx.notify();
88 }
89
90 pub fn add_right_item<T>(&mut self, item: ViewHandle<T>, cx: &mut ViewContext<Self>)
91 where
92 T: 'static + StatusItemView,
93 {
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 ItemViewHandle>,
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 Into<AnyViewHandle> for &dyn StatusItemViewHandle {
130 fn into(self) -> AnyViewHandle {
131 self.to_any()
132 }
133}