tab.rs

  1use crate::prelude::*;
  2use crate::{theme, Icon, IconColor, IconElement, Label, LabelColor};
  3
  4#[derive(Element, Clone)]
  5pub struct Tab {
  6    title: String,
  7    icon: Option<Icon>,
  8    current: bool,
  9    dirty: bool,
 10    fs_status: FileSystemStatus,
 11    git_status: GitStatus,
 12    diagnostic_status: DiagnosticStatus,
 13    close_side: IconSide,
 14}
 15
 16impl Tab {
 17    pub fn new() -> Self {
 18        Self {
 19            title: "untitled".to_string(),
 20            icon: None,
 21            current: false,
 22            dirty: false,
 23            fs_status: FileSystemStatus::None,
 24            git_status: GitStatus::None,
 25            diagnostic_status: DiagnosticStatus::None,
 26            close_side: IconSide::Right,
 27        }
 28    }
 29
 30    pub fn current(mut self, current: bool) -> Self {
 31        self.current = current;
 32        self
 33    }
 34
 35    pub fn title(mut self, title: String) -> Self {
 36        self.title = title;
 37        self
 38    }
 39
 40    pub fn icon<I>(mut self, icon: I) -> Self
 41    where
 42        I: Into<Option<Icon>>,
 43    {
 44        self.icon = icon.into();
 45        self
 46    }
 47
 48    pub fn dirty(mut self, dirty: bool) -> Self {
 49        self.dirty = dirty;
 50        self
 51    }
 52
 53    pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self {
 54        self.fs_status = fs_status;
 55        self
 56    }
 57
 58    pub fn git_status(mut self, git_status: GitStatus) -> Self {
 59        self.git_status = git_status;
 60        self
 61    }
 62
 63    pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self {
 64        self.diagnostic_status = diagnostic_status;
 65        self
 66    }
 67
 68    pub fn close_side(mut self, close_side: IconSide) -> Self {
 69        self.close_side = close_side;
 70        self
 71    }
 72
 73    fn render<V: 'static>(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl IntoElement<V> {
 74        let theme = theme(cx);
 75        let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
 76        let is_deleted = self.fs_status == FileSystemStatus::Deleted;
 77
 78        let label = match (self.git_status, is_deleted) {
 79            (_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone())
 80                .color(LabelColor::Hidden)
 81                .set_strikethrough(true),
 82            (GitStatus::None, false) => Label::new(self.title.clone()),
 83            (GitStatus::Created, false) => {
 84                Label::new(self.title.clone()).color(LabelColor::Created)
 85            }
 86            (GitStatus::Modified, false) => {
 87                Label::new(self.title.clone()).color(LabelColor::Modified)
 88            }
 89            (GitStatus::Renamed, false) => Label::new(self.title.clone()).color(LabelColor::Accent),
 90            (GitStatus::Conflict, false) => Label::new(self.title.clone()),
 91        };
 92
 93        let close_icon = IconElement::new(Icon::Close).color(IconColor::Muted);
 94
 95        div()
 96            .px_2()
 97            .py_0p5()
 98            .flex()
 99            .items_center()
100            .justify_center()
101            .fill(if self.current {
102                theme.highest.base.default.background
103            } else {
104                theme.middle.base.default.background
105            })
106            .child(
107                div()
108                    .px_1()
109                    .flex()
110                    .items_center()
111                    .gap_1()
112                    .children(has_fs_conflict.then(|| {
113                        IconElement::new(Icon::ExclamationTriangle)
114                            .size(crate::IconSize::Small)
115                            .color(IconColor::Warning)
116                    }))
117                    .children(self.icon.map(IconElement::new))
118                    .children(if self.close_side == IconSide::Left {
119                        Some(close_icon.clone())
120                    } else {
121                        None
122                    })
123                    .child(label)
124                    .children(if self.close_side == IconSide::Right {
125                        Some(close_icon)
126                    } else {
127                        None
128                    }),
129            )
130    }
131}