Allow providing a background color in a TextRun

This commit is contained in:
Antonio Scandurra
2023-11-23 18:55:16 +01:00
parent 56d043f671
commit 1ad22231d2
4 changed files with 87 additions and 12 deletions
+9 -2
View File
@@ -196,7 +196,10 @@ impl TextSystem {
let mut decoration_runs = SmallVec::<[DecorationRun; 32]>::new();
for run in runs {
if let Some(last_run) = decoration_runs.last_mut() {
if last_run.color == run.color && last_run.underline == run.underline {
if last_run.color == run.color
&& last_run.underline == run.underline
&& last_run.background_color == run.background_color
{
last_run.len += run.len as u32;
continue;
}
@@ -204,6 +207,7 @@ impl TextSystem {
decoration_runs.push(DecorationRun {
len: run.len as u32,
color: run.color,
background_color: run.background_color,
underline: run.underline.clone(),
});
}
@@ -254,13 +258,16 @@ impl TextSystem {
}
if decoration_runs.last().map_or(false, |last_run| {
last_run.color == run.color && last_run.underline == run.underline
last_run.color == run.color
&& last_run.underline == run.underline
&& last_run.background_color == run.background_color
}) {
decoration_runs.last_mut().unwrap().len += run_len_within_line as u32;
} else {
decoration_runs.push(DecorationRun {
len: run_len_within_line as u32,
color: run.color,
background_color: run.background_color,
underline: run.underline.clone(),
});
}
+59 -5
View File
@@ -1,6 +1,7 @@
use crate::{
black, point, px, BorrowWindow, Bounds, Hsla, LineLayout, Pixels, Point, Result, SharedString,
UnderlineStyle, WindowContext, WrapBoundary, WrappedLineLayout,
black, point, px, size, transparent_black, BorrowWindow, Bounds, Corners, Edges, Hsla,
LineLayout, Pixels, Point, Result, SharedString, UnderlineStyle, WindowContext, WrapBoundary,
WrappedLineLayout,
};
use derive_more::{Deref, DerefMut};
use smallvec::SmallVec;
@@ -10,6 +11,7 @@ use std::sync::Arc;
pub struct DecorationRun {
pub len: u32,
pub color: Hsla,
pub background_color: Option<Hsla>,
pub underline: Option<UnderlineStyle>,
}
@@ -97,6 +99,7 @@ fn paint_line(
let mut run_end = 0;
let mut color = black();
let mut current_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
let mut current_background: Option<(Point<Pixels>, Hsla)> = None;
let text_system = cx.text_system().clone();
let mut glyph_origin = origin;
let mut prev_glyph_position = Point::default();
@@ -110,12 +113,24 @@ fn paint_line(
if wraps.peek() == Some(&&WrapBoundary { run_ix, glyph_ix }) {
wraps.next();
if let Some((background_origin, background_color)) = current_background.take() {
cx.paint_quad(
Bounds {
origin: background_origin,
size: size(glyph_origin.x - background_origin.x, line_height),
},
Corners::default(),
background_color,
Edges::default(),
transparent_black(),
);
}
if let Some((underline_origin, underline_style)) = current_underline.take() {
cx.paint_underline(
underline_origin,
glyph_origin.x - underline_origin.x,
&underline_style,
)?;
);
}
glyph_origin.x = origin.x;
@@ -123,9 +138,20 @@ fn paint_line(
}
prev_glyph_position = glyph.position;
let mut finished_background: Option<(Point<Pixels>, Hsla)> = None;
let mut finished_underline: Option<(Point<Pixels>, UnderlineStyle)> = None;
if glyph.index >= run_end {
if let Some(style_run) = decoration_runs.next() {
if let Some((_, background_color)) = &mut current_background {
if style_run.background_color.as_ref() != Some(background_color) {
finished_background = current_background.take();
}
}
if let Some(run_background) = style_run.background_color {
current_background
.get_or_insert((point(glyph_origin.x, origin.y), run_background));
}
if let Some((_, underline_style)) = &mut current_underline {
if style_run.underline.as_ref() != Some(underline_style) {
finished_underline = current_underline.take();
@@ -149,16 +175,30 @@ fn paint_line(
color = style_run.color;
} else {
run_end = layout.len;
finished_background = current_background.take();
finished_underline = current_underline.take();
}
}
if let Some((background_origin, background_color)) = finished_background {
cx.paint_quad(
Bounds {
origin: background_origin,
size: size(glyph_origin.x - background_origin.x, line_height),
},
Corners::default(),
background_color,
Edges::default(),
transparent_black(),
);
}
if let Some((underline_origin, underline_style)) = finished_underline {
cx.paint_underline(
underline_origin,
glyph_origin.x - underline_origin.x,
&underline_style,
)?;
);
}
let max_glyph_bounds = Bounds {
@@ -188,13 +228,27 @@ fn paint_line(
}
}
if let Some((background_origin, background_color)) = current_background.take() {
let line_end_x = origin.x + wrap_width.unwrap_or(Pixels::MAX).min(layout.width);
cx.paint_quad(
Bounds {
origin: background_origin,
size: size(line_end_x - background_origin.x, line_height),
},
Corners::default(),
background_color,
Edges::default(),
transparent_black(),
);
}
if let Some((underline_start, underline_style)) = current_underline.take() {
let line_end_x = origin.x + wrap_width.unwrap_or(Pixels::MAX).min(layout.width);
cx.paint_underline(
underline_start,
line_end_x - underline_start.x,
&underline_style,
)?;
);
}
Ok(())
+1 -2
View File
@@ -881,7 +881,7 @@ impl<'a> WindowContext<'a> {
origin: Point<Pixels>,
width: Pixels,
style: &UnderlineStyle,
) -> Result<()> {
) {
let scale_factor = self.scale_factor();
let height = if style.wavy {
style.thickness * 3.
@@ -905,7 +905,6 @@ impl<'a> WindowContext<'a> {
wavy: style.wavy,
},
);
Ok(())
}
/// Paint a monochrome (non-emoji) glyph into the scene for the current frame at the current z-index.
+18 -3
View File
@@ -1,6 +1,6 @@
use gpui::{
blue, div, red, white, Div, InteractiveText, ParentElement, Render, Styled, StyledText, View,
VisualContext, WindowContext,
blue, div, green, red, white, Div, InteractiveText, ParentElement, Render, Styled, StyledText,
TextRun, View, VisualContext, WindowContext,
};
use ui::v_stack;
@@ -56,6 +56,21 @@ impl Render for TextStory {
"flex-row. width 96. The quick brown fox jumps over the lazy dog. ",
"Meanwhile, the lazy dog decided it was time for a change. ",
"He started daily workout routines, ate healthier and became the fastest dog in town.",
))).child(InteractiveText::new("interactive", StyledText::new("Hello world, how is it going?")).on_click(vec![2..4], |event, cx| {dbg!(event);}))
))).child(
InteractiveText::new(
"interactive",
StyledText::new("Hello world, how is it going?").with_runs(vec![
cx.text_style().to_run(6),
TextRun {
background_color: Some(green()),
..cx.text_style().to_run(5)
},
cx.text_style().to_run(18),
]),
)
.on_click(vec![2..4, 1..3, 7..9], |range_ix, cx| {
println!("Clicked range {range_ix}");
})
)
}
}