diff --git a/crates/copilot2/src/sign_in.rs b/crates/copilot2/src/sign_in.rs index 8da34c427f..4fa93ffcf8 100644 --- a/crates/copilot2/src/sign_in.rs +++ b/crates/copilot2/src/sign_in.rs @@ -5,7 +5,7 @@ use gpui::{ WindowBounds, WindowHandle, WindowKind, WindowOptions, }; use theme::ActiveTheme; -use ui::{h_stack, v_stack, Button, Clickable, Color, Icon, IconElement, Label}; +use ui::{prelude::*, Button, Icon, IconElement, Label}; const COPILOT_SIGN_UP_URL: &'static str = "https://github.com/features/copilot"; diff --git a/crates/diagnostics2/src/diagnostics.rs b/crates/diagnostics2/src/diagnostics.rs index 44acc285e8..f725fb7c4f 100644 --- a/crates/diagnostics2/src/diagnostics.rs +++ b/crates/diagnostics2/src/diagnostics.rs @@ -36,7 +36,7 @@ use std::{ }; use theme::ActiveTheme; pub use toolbar_controls::ToolbarControls; -use ui::{h_stack, Color, HighlightedLabel, Icon, IconElement, Label}; +use ui::{h_stack, prelude::*, HighlightedLabel, Icon, IconElement, Label}; use util::TryFutureExt; use workspace::{ item::{BreadcrumbText, Item, ItemEvent, ItemHandle}, diff --git a/crates/editor2/src/items.rs b/crates/editor2/src/items.rs index 70d4d6bf25..12feb31696 100644 --- a/crates/editor2/src/items.rs +++ b/crates/editor2/src/items.rs @@ -32,7 +32,7 @@ use std::{ }; use text::Selection; use theme::{ActiveTheme, Theme}; -use ui::{h_stack, Color, Label}; +use ui::{h_stack, prelude::*, Label}; use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt}; use workspace::{ item::{BreadcrumbText, FollowEvent, FollowableItemHandle}, diff --git a/crates/go_to_line2/src/go_to_line.rs b/crates/go_to_line2/src/go_to_line.rs index 5ad95c1f6e..aff9942c26 100644 --- a/crates/go_to_line2/src/go_to_line.rs +++ b/crates/go_to_line2/src/go_to_line.rs @@ -6,7 +6,7 @@ use gpui::{ }; use text::{Bias, Point}; use theme::ActiveTheme; -use ui::{h_stack, v_stack, Color, Label, StyledExt}; +use ui::{h_stack, prelude::*, v_stack, Label}; use util::paths::FILE_ROW_COLUMN_DELIMITER; actions!(Toggle); diff --git a/crates/ui2/src/components/label.rs b/crates/ui2/src/components/label.rs index d455a041ee..bda97be649 100644 --- a/crates/ui2/src/components/label.rs +++ b/crates/ui2/src/components/label.rs @@ -1,183 +1,7 @@ -use std::ops::Range; +mod highlighted_label; +mod label; +mod label_like; -use crate::prelude::*; -use crate::styled_ext::StyledExt; -use gpui::{relative, Div, HighlightStyle, IntoElement, StyledText, WindowContext}; - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] -pub enum LabelSize { - #[default] - Default, - Small, -} - -#[derive(Default, PartialEq, Copy, Clone)] -pub enum LineHeightStyle { - #[default] - TextLabel, - /// Sets the line height to 1 - UILabel, -} - -#[derive(IntoElement, Clone)] -pub struct Label { - label: SharedString, - size: LabelSize, - line_height_style: LineHeightStyle, - color: Color, - strikethrough: bool, -} - -impl RenderOnce for Label { - type Rendered = Div; - - fn render(self, cx: &mut WindowContext) -> Self::Rendered { - div() - .when(self.strikethrough, |this| { - this.relative().child( - div() - .absolute() - .top_1_2() - .w_full() - .h_px() - .bg(Color::Hidden.color(cx)), - ) - }) - .map(|this| match self.size { - LabelSize::Default => this.text_ui(), - LabelSize::Small => this.text_ui_sm(), - }) - .when(self.line_height_style == LineHeightStyle::UILabel, |this| { - this.line_height(relative(1.)) - }) - .text_color(self.color.color(cx)) - .child(self.label.clone()) - } -} - -impl Label { - pub fn new(label: impl Into) -> Self { - Self { - label: label.into(), - size: LabelSize::Default, - line_height_style: LineHeightStyle::default(), - color: Color::Default, - strikethrough: false, - } - } - - pub fn size(mut self, size: LabelSize) -> Self { - self.size = size; - self - } - - pub fn color(mut self, color: Color) -> Self { - self.color = color; - self - } - - pub fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self { - self.line_height_style = line_height_style; - self - } - - pub fn set_strikethrough(mut self, strikethrough: bool) -> Self { - self.strikethrough = strikethrough; - self - } -} - -#[derive(IntoElement)] -pub struct HighlightedLabel { - label: SharedString, - size: LabelSize, - color: Color, - highlight_indices: Vec, - strikethrough: bool, -} - -impl RenderOnce for HighlightedLabel { - type Rendered = Div; - - fn render(self, cx: &mut WindowContext) -> Self::Rendered { - let highlight_color = cx.theme().colors().text_accent; - - let mut highlight_indices = self.highlight_indices.iter().copied().peekable(); - let mut highlights: Vec<(Range, HighlightStyle)> = Vec::new(); - - while let Some(start_ix) = highlight_indices.next() { - let mut end_ix = start_ix; - - loop { - end_ix = end_ix + self.label[end_ix..].chars().next().unwrap().len_utf8(); - if let Some(&next_ix) = highlight_indices.peek() { - if next_ix == end_ix { - end_ix = next_ix; - highlight_indices.next(); - continue; - } - } - break; - } - - highlights.push(( - start_ix..end_ix, - HighlightStyle { - color: Some(highlight_color), - ..Default::default() - }, - )); - } - - let mut text_style = cx.text_style().clone(); - text_style.color = self.color.color(cx); - - div() - .flex() - .when(self.strikethrough, |this| { - this.relative().child( - div() - .absolute() - .top_px() - .my_auto() - .w_full() - .h_px() - .bg(Color::Hidden.color(cx)), - ) - }) - .map(|this| match self.size { - LabelSize::Default => this.text_ui(), - LabelSize::Small => this.text_ui_sm(), - }) - .child(StyledText::new(self.label).with_highlights(&text_style, highlights)) - } -} - -impl HighlightedLabel { - /// shows a label with the given characters highlighted. - /// characters are identified by utf8 byte position. - pub fn new(label: impl Into, highlight_indices: Vec) -> Self { - Self { - label: label.into(), - size: LabelSize::Default, - color: Color::Default, - highlight_indices, - strikethrough: false, - } - } - - pub fn size(mut self, size: LabelSize) -> Self { - self.size = size; - self - } - - pub fn color(mut self, color: Color) -> Self { - self.color = color; - self - } - - pub fn set_strikethrough(mut self, strikethrough: bool) -> Self { - self.strikethrough = strikethrough; - self - } -} +pub use highlighted_label::*; +pub use label::*; +pub use label_like::*; diff --git a/crates/ui2/src/components/label/highlighted_label.rs b/crates/ui2/src/components/label/highlighted_label.rs new file mode 100644 index 0000000000..a7fbb0d816 --- /dev/null +++ b/crates/ui2/src/components/label/highlighted_label.rs @@ -0,0 +1,86 @@ +use std::ops::Range; + +use gpui::{HighlightStyle, StyledText}; + +use crate::{prelude::*, LabelCommon, LabelLike, LabelSize, LineHeightStyle}; + +#[derive(IntoElement)] +pub struct HighlightedLabel { + base: LabelLike, + label: SharedString, + highlight_indices: Vec, +} + +impl HighlightedLabel { + /// Constructs a label with the given characters highlighted. + /// Characters are identified by UTF-8 byte position. + pub fn new(label: impl Into, highlight_indices: Vec) -> Self { + Self { + base: LabelLike::new(), + label: label.into(), + highlight_indices, + } + } +} + +impl LabelCommon for HighlightedLabel { + fn size(mut self, size: LabelSize) -> Self { + self.base = self.base.size(size); + self + } + + fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self { + self.base = self.base.line_height_style(line_height_style); + self + } + + fn color(mut self, color: Color) -> Self { + self.base = self.base.color(color); + self + } + + fn strikethrough(mut self, strikethrough: bool) -> Self { + self.base = self.base.strikethrough(strikethrough); + self + } +} + +impl RenderOnce for HighlightedLabel { + type Rendered = LabelLike; + + fn render(self, cx: &mut WindowContext) -> Self::Rendered { + let highlight_color = cx.theme().colors().text_accent; + + let mut highlight_indices = self.highlight_indices.iter().copied().peekable(); + let mut highlights: Vec<(Range, HighlightStyle)> = Vec::new(); + + while let Some(start_ix) = highlight_indices.next() { + let mut end_ix = start_ix; + + loop { + end_ix = end_ix + self.label[end_ix..].chars().next().unwrap().len_utf8(); + if let Some(&next_ix) = highlight_indices.peek() { + if next_ix == end_ix { + end_ix = next_ix; + highlight_indices.next(); + continue; + } + } + break; + } + + highlights.push(( + start_ix..end_ix, + HighlightStyle { + color: Some(highlight_color), + ..Default::default() + }, + )); + } + + let mut text_style = cx.text_style().clone(); + text_style.color = self.base.color.color(cx); + + LabelLike::new().child(StyledText::new(self.label).with_highlights(&text_style, highlights)) + } +} diff --git a/crates/ui2/src/components/label/label.rs b/crates/ui2/src/components/label/label.rs new file mode 100644 index 0000000000..8272340888 --- /dev/null +++ b/crates/ui2/src/components/label/label.rs @@ -0,0 +1,48 @@ +use gpui::WindowContext; + +use crate::{prelude::*, LabelCommon, LabelLike, LabelSize, LineHeightStyle}; + +#[derive(IntoElement)] +pub struct Label { + base: LabelLike, + label: SharedString, +} + +impl Label { + pub fn new(label: impl Into) -> Self { + Self { + base: LabelLike::new(), + label: label.into(), + } + } +} + +impl LabelCommon for Label { + fn size(mut self, size: LabelSize) -> Self { + self.base = self.base.size(size); + self + } + + fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self { + self.base = self.base.line_height_style(line_height_style); + self + } + + fn color(mut self, color: Color) -> Self { + self.base = self.base.color(color); + self + } + + fn strikethrough(mut self, strikethrough: bool) -> Self { + self.base = self.base.strikethrough(strikethrough); + self + } +} + +impl RenderOnce for Label { + type Rendered = LabelLike; + + fn render(self, _cx: &mut WindowContext) -> Self::Rendered { + self.base.child(self.label) + } +} diff --git a/crates/ui2/src/components/label/label_like.rs b/crates/ui2/src/components/label/label_like.rs new file mode 100644 index 0000000000..72a48adea4 --- /dev/null +++ b/crates/ui2/src/components/label/label_like.rs @@ -0,0 +1,102 @@ +use gpui::{relative, AnyElement, Div, Styled}; +use smallvec::SmallVec; + +use crate::prelude::*; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)] +pub enum LabelSize { + #[default] + Default, + Small, +} + +#[derive(Default, PartialEq, Copy, Clone)] +pub enum LineHeightStyle { + #[default] + TextLabel, + /// Sets the line height to 1 + UILabel, +} + +pub trait LabelCommon { + fn size(self, size: LabelSize) -> Self; + fn line_height_style(self, line_height_style: LineHeightStyle) -> Self; + fn color(self, color: Color) -> Self; + fn strikethrough(self, strikethrough: bool) -> Self; +} + +#[derive(IntoElement)] +pub struct LabelLike { + size: LabelSize, + line_height_style: LineHeightStyle, + pub(crate) color: Color, + strikethrough: bool, + children: SmallVec<[AnyElement; 2]>, +} + +impl LabelLike { + pub fn new() -> Self { + Self { + size: LabelSize::Default, + line_height_style: LineHeightStyle::default(), + color: Color::Default, + strikethrough: false, + children: SmallVec::new(), + } + } +} + +impl LabelCommon for LabelLike { + fn size(mut self, size: LabelSize) -> Self { + self.size = size; + self + } + + fn line_height_style(mut self, line_height_style: LineHeightStyle) -> Self { + self.line_height_style = line_height_style; + self + } + + fn color(mut self, color: Color) -> Self { + self.color = color; + self + } + + fn strikethrough(mut self, strikethrough: bool) -> Self { + self.strikethrough = strikethrough; + self + } +} + +impl ParentElement for LabelLike { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + &mut self.children + } +} + +impl RenderOnce for LabelLike { + type Rendered = Div; + + fn render(self, cx: &mut WindowContext) -> Self::Rendered { + div() + .when(self.strikethrough, |this| { + this.relative().child( + div() + .absolute() + .top_1_2() + .w_full() + .h_px() + .bg(Color::Hidden.color(cx)), + ) + }) + .map(|this| match self.size { + LabelSize::Default => this.text_ui(), + LabelSize::Small => this.text_ui_sm(), + }) + .when(self.line_height_style == LineHeightStyle::UILabel, |this| { + this.line_height(relative(1.)) + }) + .text_color(self.color.color(cx)) + .children(self.children) + } +} diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 38065b6275..a71efa4dc3 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -9,5 +9,5 @@ pub use crate::disableable::*; pub use crate::fixed::*; pub use crate::selectable::*; pub use crate::{h_stack, v_stack}; -pub use crate::{ButtonCommon, Color, StyledExt}; +pub use crate::{ButtonCommon, Color, LabelCommon, StyledExt}; pub use theme::ActiveTheme;