summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/src/text.rs10
-rw-r--r--widget/src/text/rich.rs90
2 files changed, 79 insertions, 21 deletions
diff --git a/core/src/text.rs b/core/src/text.rs
index 2f085bd8..68c586f1 100644
--- a/core/src/text.rs
+++ b/core/src/text.rs
@@ -245,6 +245,8 @@ pub struct Span<'a, Link = (), Font = crate::Font> {
///
/// Currently, it only affects the bounds of the [`Highlight`].
pub padding: Padding,
+ /// Whether the [`Span`] should be underlined or not.
+ pub underline: bool,
}
/// A text highlight.
@@ -268,6 +270,7 @@ impl<'a, Link, Font> Span<'a, Link, Font> {
highlight: None,
link: None,
padding: Padding::ZERO,
+ underline: false,
}
}
@@ -386,6 +389,12 @@ impl<'a, Link, Font> Span<'a, Link, Font> {
self
}
+ /// Sets whether the [`Span`] shoud be underlined or not.
+ pub fn underline(mut self, underline: bool) -> Self {
+ self.underline = underline;
+ self
+ }
+
/// Turns the [`Span`] into a static one.
pub fn to_static(self) -> Span<'static, Link, Font> {
Span {
@@ -397,6 +406,7 @@ impl<'a, Link, Font> Span<'a, Link, Font> {
link: self.link,
highlight: self.highlight,
padding: self.padding,
+ underline: self.underline,
}
}
}
diff --git a/widget/src/text/rich.rs b/widget/src/text/rich.rs
index 9935e6c5..096056d4 100644
--- a/widget/src/text/rich.rs
+++ b/widget/src/text/rich.rs
@@ -237,7 +237,7 @@ where
theme: &Theme,
defaults: &renderer::Style,
layout: Layout<'_>,
- _cursor_position: mouse::Cursor,
+ cursor: mouse::Cursor,
viewport: &Rectangle,
) {
let state = tree
@@ -246,29 +246,77 @@ where
let style = theme.style(&self.class);
+ let hovered_span = cursor
+ .position_in(layout.bounds())
+ .and_then(|position| state.paragraph.hit_span(position));
+
for (index, span) in self.spans.iter().enumerate() {
- if let Some(highlight) = span.highlight {
+ let is_hovered_link =
+ span.link.is_some() && Some(index) == hovered_span;
+
+ if span.highlight.is_some() || span.underline || is_hovered_link {
let translation = layout.position() - Point::ORIGIN;
+ let regions = state.paragraph.span_bounds(index);
+
+ if let Some(highlight) = span.highlight {
+ for bounds in &regions {
+ let bounds = Rectangle::new(
+ bounds.position()
+ - Vector::new(
+ span.padding.left,
+ span.padding.top,
+ ),
+ bounds.size()
+ + Size::new(
+ span.padding.horizontal(),
+ span.padding.vertical(),
+ ),
+ );
+
+ renderer.fill_quad(
+ renderer::Quad {
+ bounds: bounds + translation,
+ border: highlight.border,
+ ..Default::default()
+ },
+ highlight.background,
+ );
+ }
+ }
- for bounds in state.paragraph.span_bounds(index) {
- let bounds = Rectangle::new(
- bounds.position()
- - Vector::new(span.padding.left, span.padding.top),
- bounds.size()
- + Size::new(
- span.padding.horizontal(),
- span.padding.vertical(),
- ),
- );
-
- renderer.fill_quad(
- renderer::Quad {
- bounds: bounds + translation,
- border: highlight.border,
- ..Default::default()
- },
- highlight.background,
- );
+ if span.underline || is_hovered_link {
+ let size = span
+ .size
+ .or(self.size)
+ .unwrap_or(renderer.default_size());
+
+ let line_height = span
+ .line_height
+ .unwrap_or(self.line_height)
+ .to_absolute(size);
+
+ for bounds in regions {
+ renderer.fill_quad(
+ renderer::Quad {
+ bounds: Rectangle::new(
+ bounds.position()
+ + translation
+ + Vector::new(
+ 0.0,
+ size.0
+ + (line_height.0 - size.0)
+ / 2.0
+ - size.0 * 0.08,
+ ),
+ Size::new(bounds.width, 1.0),
+ ),
+ ..Default::default()
+ },
+ span.color
+ .or(style.color)
+ .unwrap_or(defaults.text_color),
+ );
+ }
}
}
}