label_like.rs

  1#![allow(missing_docs)]
  2
  3use gpui::{relative, AnyElement, FontWeight, StyleRefinement, Styled, UnderlineStyle};
  4use settings::Settings;
  5use smallvec::SmallVec;
  6use theme::ThemeSettings;
  7
  8use crate::prelude::*;
  9
 10#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
 11pub enum LabelSize {
 12    #[default]
 13    Default,
 14    Large,
 15    Small,
 16    XSmall,
 17}
 18
 19#[derive(Default, PartialEq, Copy, Clone)]
 20pub enum LineHeightStyle {
 21    #[default]
 22    TextLabel,
 23    /// Sets the line height to 1.
 24    UiLabel,
 25}
 26
 27/// A common set of traits all labels must implement.
 28pub trait LabelCommon {
 29    /// Sets the size of the label using a [`LabelSize`].
 30    fn size(self, size: LabelSize) -> Self;
 31
 32    /// Sets the font weight of the label.
 33    fn weight(self, weight: FontWeight) -> Self;
 34
 35    /// Sets the line height style of the label using a [`LineHeightStyle`].
 36    fn line_height_style(self, line_height_style: LineHeightStyle) -> Self;
 37
 38    /// Sets the color of the label using a [`Color`].
 39    fn color(self, color: Color) -> Self;
 40
 41    /// Sets the strikethrough property of the label.
 42    fn strikethrough(self, strikethrough: bool) -> Self;
 43
 44    /// Sets the italic property of the label.
 45    fn italic(self, italic: bool) -> Self;
 46
 47    /// Sets the underline property of the label
 48    fn underline(self, underline: bool) -> Self;
 49
 50    /// Sets the alpha property of the label, overwriting the alpha value of the color.
 51    fn alpha(self, alpha: f32) -> Self;
 52
 53    /// Truncates overflowing text with an ellipsis (`…`) if needed.
 54    fn text_ellipsis(self) -> Self;
 55
 56    /// Sets the label to render as a single line.
 57    fn single_line(self) -> Self;
 58
 59    /// Sets the font to the buffer's
 60    fn buffer_font(self, cx: &App) -> Self;
 61}
 62
 63#[derive(IntoElement)]
 64pub struct LabelLike {
 65    pub(super) base: Div,
 66    size: LabelSize,
 67    weight: Option<FontWeight>,
 68    line_height_style: LineHeightStyle,
 69    pub(crate) color: Color,
 70    strikethrough: bool,
 71    italic: bool,
 72    children: SmallVec<[AnyElement; 2]>,
 73    alpha: Option<f32>,
 74    underline: bool,
 75    single_line: bool,
 76    text_ellipsis: bool,
 77}
 78
 79impl Default for LabelLike {
 80    fn default() -> Self {
 81        Self::new()
 82    }
 83}
 84
 85impl LabelLike {
 86    pub fn new() -> Self {
 87        Self {
 88            base: div(),
 89            size: LabelSize::Default,
 90            weight: None,
 91            line_height_style: LineHeightStyle::default(),
 92            color: Color::Default,
 93            strikethrough: false,
 94            italic: false,
 95            children: SmallVec::new(),
 96            alpha: None,
 97            underline: false,
 98            single_line: false,
 99            text_ellipsis: false,
100        }
101    }
102}
103
104// Style methods.
105impl LabelLike {
106    fn style(&mut self) -> &mut StyleRefinement {
107        self.base.style()
108    }
109
110    gpui::margin_style_methods!({
111        visibility: pub
112    });
113}
114
115impl LabelCommon for LabelLike {
116    fn size(mut self, size: LabelSize) -> Self {
117        self.size = size;
118        self
119    }
120
121    fn weight(mut self, weight: FontWeight) -> Self {
122        self.weight = Some(weight);
123        self
124    }
125
126    fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self {
127        self.line_height_style = line_height_style;
128        self
129    }
130
131    fn color(mut self, color: Color) -> Self {
132        self.color = color;
133        self
134    }
135
136    fn strikethrough(mut self, strikethrough: bool) -> Self {
137        self.strikethrough = strikethrough;
138        self
139    }
140
141    fn italic(mut self, italic: bool) -> Self {
142        self.italic = italic;
143        self
144    }
145
146    fn underline(mut self, underline: bool) -> Self {
147        self.underline = underline;
148        self
149    }
150
151    fn alpha(mut self, alpha: f32) -> Self {
152        self.alpha = Some(alpha);
153        self
154    }
155
156    fn text_ellipsis(mut self) -> Self {
157        self.text_ellipsis = true;
158        self
159    }
160
161    fn single_line(mut self) -> Self {
162        self.single_line = true;
163        self
164    }
165
166    fn buffer_font(mut self, cx: &App) -> Self {
167        self.base = self
168            .base
169            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone());
170        self
171    }
172}
173
174impl ParentElement for LabelLike {
175    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
176        self.children.extend(elements)
177    }
178}
179
180impl RenderOnce for LabelLike {
181    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
182        let mut color = self.color.color(cx);
183        if let Some(alpha) = self.alpha {
184            color.fade_out(1.0 - alpha);
185        }
186
187        self.base
188            .map(|this| match self.size {
189                LabelSize::Large => this.text_ui_lg(cx),
190                LabelSize::Default => this.text_ui(cx),
191                LabelSize::Small => this.text_ui_sm(cx),
192                LabelSize::XSmall => this.text_ui_xs(cx),
193            })
194            .when(self.line_height_style == LineHeightStyle::UiLabel, |this| {
195                this.line_height(relative(1.))
196            })
197            .when(self.italic, |this| this.italic())
198            .when(self.underline, |mut this| {
199                this.text_style()
200                    .get_or_insert_with(Default::default)
201                    .underline = Some(UnderlineStyle {
202                    thickness: px(1.),
203                    color: None,
204                    wavy: false,
205                });
206                this
207            })
208            .when(self.strikethrough, |this| this.line_through())
209            .when(self.single_line, |this| this.whitespace_nowrap())
210            .when(self.text_ellipsis, |this| {
211                this.overflow_x_hidden().text_ellipsis()
212            })
213            .text_color(color)
214            .font_weight(
215                self.weight
216                    .unwrap_or(ThemeSettings::get_global(cx).ui_font.weight),
217            )
218            .children(self.children)
219    }
220}