toolbar.rs

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