label_like.rs

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