From 4069db49599434afdc3c0cbe6d4f1469a29d92b1 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 26 Oct 2021 12:46:46 -0700 Subject: [PATCH] Allow underlines to have different color than the text Co-Authored-By: Nathan Sobo --- crates/editor/src/element.rs | 8 +++--- crates/editor/src/lib.rs | 2 +- crates/gpui/examples/text.rs | 4 +-- crates/gpui/src/elements/label.rs | 4 +-- crates/gpui/src/fonts.rs | 39 ++++++++++++++++++++------- crates/gpui/src/platform/mac/fonts.rs | 12 ++++----- crates/gpui/src/text_layout.rs | 34 +++++++++++------------ crates/workspace/src/items.rs | 2 +- 8 files changed, 63 insertions(+), 42 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index cf0a101b0feaa8490888ca1aef1aec71ff8513a5..b18e72b2d77199e263e46b2f04cfee5e2acc9d55 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -394,7 +394,7 @@ impl EditorElement { RunStyle { font_id: style.text.font_id, color: Color::black(), - underline: false, + underline: None, }, )], ) @@ -435,7 +435,7 @@ impl EditorElement { RunStyle { font_id: style.text.font_id, color, - underline: false, + underline: None, }, )], ))); @@ -476,7 +476,7 @@ impl EditorElement { RunStyle { font_id: placeholder_style.font_id, color: placeholder_style.color, - underline: false, + underline: None, }, )], ) @@ -859,7 +859,7 @@ impl LayoutState { RunStyle { font_id: self.style.text.font_id, color: Color::black(), - underline: false, + underline: None, }, )], ) diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index b2a97982b70c86c50375c21b2f1e2a59cbf78917..cb813350a0c2a009fc070e56ea05c214e47e3ed5 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -2763,7 +2763,7 @@ impl EditorSettings { font_size: 14., color: Color::from_u32(0xff0000ff), font_properties, - underline: false, + underline: None, }, placeholder_text: None, background: Default::default(), diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 6c82b2d88a3df891ce9ae9b120d0e24496f790fb..fb4772d11ccd61a620f49dadd79586d89346b8e7 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -62,7 +62,7 @@ impl gpui::Element for TextElement { .select_font(family, &Default::default()) .unwrap(), color: Color::default(), - underline: false, + underline: None, }; let bold = RunStyle { font_id: cx @@ -76,7 +76,7 @@ impl gpui::Element for TextElement { ) .unwrap(), color: Color::default(), - underline: false, + underline: None, }; let text = "Hello world!"; diff --git a/crates/gpui/src/elements/label.rs b/crates/gpui/src/elements/label.rs index 33274ffaeb8663e08e0ecccebb92ce5faa34dd2f..f78e3973e9670884594d6c82201c379638c2d3d3 100644 --- a/crates/gpui/src/elements/label.rs +++ b/crates/gpui/src/elements/label.rs @@ -207,7 +207,7 @@ mod tests { "Menlo", 12., Default::default(), - false, + None, Color::black(), cx.font_cache(), ) @@ -216,7 +216,7 @@ mod tests { "Menlo", 12., *FontProperties::new().weight(Weight::BOLD), - false, + None, Color::new(255, 0, 0, 255), cx.font_cache(), ) diff --git a/crates/gpui/src/fonts.rs b/crates/gpui/src/fonts.rs index 4ac7a92bc4c0b382c1835612d8dca5af767c36ec..b1aae4c9be323aa54bbd23b4ff4aa463e4a0882e 100644 --- a/crates/gpui/src/fonts.rs +++ b/crates/gpui/src/fonts.rs @@ -27,14 +27,14 @@ pub struct TextStyle { pub font_id: FontId, pub font_size: f32, pub font_properties: Properties, - pub underline: bool, + pub underline: Option, } #[derive(Clone, Debug, Default)] pub struct HighlightStyle { pub color: Color, pub font_properties: Properties, - pub underline: bool, + pub underline: Option, } #[allow(non_camel_case_types)] @@ -64,7 +64,7 @@ struct TextStyleJson { #[serde(default)] italic: bool, #[serde(default)] - underline: bool, + underline: UnderlineStyleJson, } #[derive(Deserialize)] @@ -74,7 +74,14 @@ struct HighlightStyleJson { #[serde(default)] italic: bool, #[serde(default)] - underline: bool, + underline: UnderlineStyleJson, +} + +#[derive(Deserialize)] +#[serde(untagged)] +enum UnderlineStyleJson { + Underlined(bool), + UnderlinedWithColor(Color), } impl TextStyle { @@ -82,7 +89,7 @@ impl TextStyle { font_family_name: impl Into>, font_size: f32, font_properties: Properties, - underline: bool, + underline: Option, color: Color, font_cache: &FontCache, ) -> anyhow::Result { @@ -116,7 +123,7 @@ impl TextStyle { json.family, json.size, font_properties, - json.underline, + underline_from_json(json.underline, json.color), json.color, font_cache, ) @@ -167,6 +174,12 @@ impl From for HighlightStyle { } } +impl Default for UnderlineStyleJson { + fn default() -> Self { + Self::Underlined(false) + } +} + impl Default for TextStyle { fn default() -> Self { FONT_CACHE.with(|font_cache| { @@ -199,7 +212,7 @@ impl HighlightStyle { Self { color: json.color, font_properties, - underline: json.underline, + underline: underline_from_json(json.underline, json.color), } } } @@ -209,7 +222,7 @@ impl From for HighlightStyle { Self { color, font_properties: Default::default(), - underline: false, + underline: None, } } } @@ -248,12 +261,20 @@ impl<'de> Deserialize<'de> for HighlightStyle { Ok(Self { color: serde_json::from_value(json).map_err(de::Error::custom)?, font_properties: Properties::new(), - underline: false, + underline: None, }) } } } +fn underline_from_json(json: UnderlineStyleJson, text_color: Color) -> Option { + match json { + UnderlineStyleJson::Underlined(false) => None, + UnderlineStyleJson::Underlined(true) => Some(text_color), + UnderlineStyleJson::UnderlinedWithColor(color) => Some(color), + } +} + fn properties_from_json(weight: Option, italic: bool) -> Properties { let weight = match weight.unwrap_or(WeightJson::normal) { WeightJson::thin => Weight::THIN, diff --git a/crates/gpui/src/platform/mac/fonts.rs b/crates/gpui/src/platform/mac/fonts.rs index c01700ce22817b341dca6caf634490a3a0b24666..c7f03689ee677bb017bcd42224e182c84f9b2bf2 100644 --- a/crates/gpui/src/platform/mac/fonts.rs +++ b/crates/gpui/src/platform/mac/fonts.rs @@ -417,21 +417,21 @@ mod tests { let menlo_regular = RunStyle { font_id: fonts.select_font(&menlo, &Properties::new()).unwrap(), color: Default::default(), - underline: false, + underline: None, }; let menlo_italic = RunStyle { font_id: fonts .select_font(&menlo, &Properties::new().style(Style::Italic)) .unwrap(), color: Default::default(), - underline: false, + underline: None, }; let menlo_bold = RunStyle { font_id: fonts .select_font(&menlo, &Properties::new().weight(Weight::BOLD)) .unwrap(), color: Default::default(), - underline: false, + underline: None, }; assert_ne!(menlo_regular, menlo_italic); assert_ne!(menlo_regular, menlo_bold); @@ -458,13 +458,13 @@ mod tests { let zapfino_regular = RunStyle { font_id: fonts.select_font(&zapfino, &Properties::new())?, color: Default::default(), - underline: false, + underline: None, }; let menlo = fonts.load_family("Menlo")?; let menlo_regular = RunStyle { font_id: fonts.select_font(&menlo, &Properties::new())?, color: Default::default(), - underline: false, + underline: None, }; let text = "This is, m𐍈re 𐍈r less, Zapfino!𐍈"; @@ -543,7 +543,7 @@ mod tests { let style = RunStyle { font_id: fonts.select_font(&font_ids, &Default::default()).unwrap(), color: Default::default(), - underline: false, + underline: None, }; let line = "\u{feff}"; diff --git a/crates/gpui/src/text_layout.rs b/crates/gpui/src/text_layout.rs index a7b976d72c746fe010ccd3a3ad0ebccdd8884917..105dae7c9279923f114133b438e0a51b03cce674 100644 --- a/crates/gpui/src/text_layout.rs +++ b/crates/gpui/src/text_layout.rs @@ -28,7 +28,7 @@ pub struct TextLayoutCache { pub struct RunStyle { pub color: Color, pub font_id: FontId, - pub underline: bool, + pub underline: Option, } impl TextLayoutCache { @@ -167,7 +167,7 @@ impl<'a> Hash for CacheKeyRef<'a> { #[derive(Default, Debug)] pub struct Line { layout: Arc, - style_runs: SmallVec<[(u32, Color, bool); 32]>, + style_runs: SmallVec<[(u32, Color, Option); 32]>, } #[derive(Default, Debug)] @@ -249,7 +249,7 @@ impl Line { let mut style_runs = self.style_runs.iter(); let mut run_end = 0; let mut color = Color::black(); - let mut underline_start = None; + let mut underline = None; for run in &self.layout.runs { let max_glyph_width = cx @@ -268,24 +268,24 @@ impl Line { } if glyph.index >= run_end { - if let Some((run_len, run_color, run_underlined)) = style_runs.next() { - if let Some(underline_origin) = underline_start { - if !*run_underlined || *run_color != color { + if let Some((run_len, run_color, run_underline_color)) = style_runs.next() { + if let Some((underline_origin, underline_color)) = underline { + if *run_underline_color != Some(underline_color) { cx.scene.push_underline(scene::Quad { bounds: RectF::from_points( underline_origin, glyph_origin + vec2f(0., 1.), ), - background: Some(color), + background: Some(underline_color), border: Default::default(), corner_radius: 0., }); - underline_start = None; + underline = None; } } - if *run_underlined { - underline_start.get_or_insert(glyph_origin); + if let Some(run_underline_color) = run_underline_color { + underline.get_or_insert((glyph_origin, *run_underline_color)); } run_end += *run_len as usize; @@ -293,13 +293,13 @@ impl Line { } else { run_end = self.layout.len; color = Color::black(); - if let Some(underline_origin) = underline_start.take() { + if let Some((underline_origin, underline_color)) = underline.take() { cx.scene.push_underline(scene::Quad { bounds: RectF::from_points( underline_origin, glyph_origin + vec2f(0., 1.), ), - background: Some(color), + background: Some(underline_color), border: Default::default(), corner_radius: 0., }); @@ -317,12 +317,12 @@ impl Line { } } - if let Some(underline_start) = underline_start.take() { + if let Some((underline_start, underline_color)) = underline.take() { let line_end = origin + baseline_offset + vec2f(self.layout.width, 0.); cx.scene.push_underline(scene::Quad { bounds: RectF::from_points(underline_start, line_end + vec2f(0., 1.)), - background: Some(color), + background: Some(underline_color), border: Default::default(), corner_radius: 0., }); @@ -597,7 +597,7 @@ impl LineWrapper { RunStyle { font_id: self.font_id, color: Default::default(), - underline: false, + underline: None, }, )], ) @@ -681,7 +681,7 @@ mod tests { let normal = RunStyle { font_id, color: Default::default(), - underline: false, + underline: None, }; let bold = RunStyle { font_id: font_cache @@ -694,7 +694,7 @@ mod tests { ) .unwrap(), color: Default::default(), - underline: false, + underline: None, }; let text = "aa bbb cccc ddddd eeee"; diff --git a/crates/workspace/src/items.rs b/crates/workspace/src/items.rs index 9370ac7f85e3b4226140bcc2c124b2db670db967..d1275aee7c5f60204785c087bad23ae8a835eacf 100644 --- a/crates/workspace/src/items.rs +++ b/crates/workspace/src/items.rs @@ -37,7 +37,7 @@ impl Item for Buffer { font_id, font_size, font_properties, - underline: false, + underline: None, }; EditorSettings { tab_size: settings.tab_size,