list_header.rs

  1use std::rc::Rc;
  2
  3use gpui::{ClickEvent, Div};
  4
  5use crate::prelude::*;
  6use crate::{h_stack, Disclosure, Icon, IconButton, IconElement, IconSize, Label, Toggleable};
  7
  8pub enum ListHeaderMeta {
  9    Tools(Vec<IconButton>),
 10    // TODO: This should be a button
 11    Button(Label),
 12    Text(Label),
 13}
 14
 15#[derive(IntoElement)]
 16pub struct ListHeader {
 17    label: SharedString,
 18    left_icon: Option<Icon>,
 19    meta: Option<ListHeaderMeta>,
 20    toggle: Toggleable,
 21    on_toggle: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
 22    inset: bool,
 23    selected: bool,
 24}
 25
 26impl ListHeader {
 27    pub fn new(label: impl Into<SharedString>) -> Self {
 28        Self {
 29            label: label.into(),
 30            left_icon: None,
 31            meta: None,
 32            inset: false,
 33            toggle: Toggleable::NotToggleable,
 34            on_toggle: None,
 35            selected: false,
 36        }
 37    }
 38
 39    pub fn toggle(mut self, toggle: Toggleable) -> Self {
 40        self.toggle = toggle;
 41        self
 42    }
 43
 44    pub fn on_toggle(
 45        mut self,
 46        on_toggle: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
 47    ) -> Self {
 48        self.on_toggle = Some(Rc::new(on_toggle));
 49        self
 50    }
 51
 52    pub fn left_icon(mut self, left_icon: Option<Icon>) -> Self {
 53        self.left_icon = left_icon;
 54        self
 55    }
 56
 57    pub fn right_button(self, button: IconButton) -> Self {
 58        self.meta(Some(ListHeaderMeta::Tools(vec![button])))
 59    }
 60
 61    pub fn meta(mut self, meta: Option<ListHeaderMeta>) -> Self {
 62        self.meta = meta;
 63        self
 64    }
 65
 66    pub fn selected(mut self, selected: bool) -> Self {
 67        self.selected = selected;
 68        self
 69    }
 70}
 71
 72impl RenderOnce for ListHeader {
 73    type Rendered = Div;
 74
 75    fn render(self, cx: &mut WindowContext) -> Self::Rendered {
 76        let meta = match self.meta {
 77            Some(ListHeaderMeta::Tools(icons)) => div().child(
 78                h_stack()
 79                    .gap_2()
 80                    .items_center()
 81                    .children(icons.into_iter().map(|i| i.color(Color::Muted))),
 82            ),
 83            Some(ListHeaderMeta::Button(label)) => div().child(label),
 84            Some(ListHeaderMeta::Text(label)) => div().child(label),
 85            None => div(),
 86        };
 87
 88        h_stack().w_full().relative().child(
 89            div()
 90                .h_5()
 91                .when(self.inset, |this| this.px_2())
 92                .when(self.selected, |this| {
 93                    this.bg(cx.theme().colors().ghost_element_selected)
 94                })
 95                .flex()
 96                .flex_1()
 97                .items_center()
 98                .justify_between()
 99                .w_full()
100                .gap_1()
101                .child(
102                    h_stack()
103                        .gap_1()
104                        .child(
105                            div()
106                                .flex()
107                                .gap_1()
108                                .items_center()
109                                .children(self.left_icon.map(|i| {
110                                    IconElement::new(i)
111                                        .color(Color::Muted)
112                                        .size(IconSize::Small)
113                                }))
114                                .child(Label::new(self.label.clone()).color(Color::Muted)),
115                        )
116                        .children(
117                            Disclosure::from_toggleable(self.toggle)
118                                .map(|disclosure| disclosure.on_toggle(self.on_toggle)),
119                        ),
120                )
121                .child(meta),
122        )
123    }
124}