list.rs

 1#![allow(missing_docs)]
 2
 3use gpui::AnyElement;
 4use smallvec::SmallVec;
 5
 6use crate::{prelude::*, v_flex, Label, ListHeader};
 7
 8pub enum EmptyMessage {
 9    Text(SharedString),
10    Element(AnyElement),
11}
12
13#[derive(IntoElement)]
14pub struct List {
15    /// Message to display when the list is empty
16    /// Defaults to "No items"
17    empty_message: EmptyMessage,
18    header: Option<ListHeader>,
19    toggle: Option<bool>,
20    children: SmallVec<[AnyElement; 2]>,
21}
22
23impl Default for List {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl List {
30    pub fn new() -> Self {
31        Self {
32            empty_message: EmptyMessage::Text("No items".into()),
33            header: None,
34            toggle: None,
35            children: SmallVec::new(),
36        }
37    }
38
39    pub fn empty_message(mut self, message: impl Into<EmptyMessage>) -> Self {
40        self.empty_message = message.into();
41        self
42    }
43
44    pub fn header(mut self, header: impl Into<Option<ListHeader>>) -> Self {
45        self.header = header.into();
46        self
47    }
48
49    pub fn toggle(mut self, toggle: impl Into<Option<bool>>) -> Self {
50        self.toggle = toggle.into();
51        self
52    }
53}
54
55impl ParentElement for List {
56    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
57        self.children.extend(elements)
58    }
59}
60
61impl From<String> for EmptyMessage {
62    fn from(s: String) -> Self {
63        EmptyMessage::Text(SharedString::from(s))
64    }
65}
66
67impl From<&str> for EmptyMessage {
68    fn from(s: &str) -> Self {
69        EmptyMessage::Text(SharedString::from(s.to_owned()))
70    }
71}
72
73impl From<AnyElement> for EmptyMessage {
74    fn from(e: AnyElement) -> Self {
75        EmptyMessage::Element(e)
76    }
77}
78
79impl RenderOnce for List {
80    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
81        v_flex()
82            .w_full()
83            .py(DynamicSpacing::Base04.rems(cx))
84            .children(self.header)
85            .map(|this| match (self.children.is_empty(), self.toggle) {
86                (false, _) => this.children(self.children),
87                (true, Some(false)) => this,
88                (true, _) => match self.empty_message {
89                    EmptyMessage::Text(text) => this.child(Label::new(text).color(Color::Muted)),
90                    EmptyMessage::Element(element) => this.child(element),
91                },
92            })
93    }
94}