aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/text/rich.rs75
1 files changed, 63 insertions, 12 deletions
diff --git a/src/text/rich.rs b/src/text/rich.rs
index 3268160..a30663b 100644
--- a/src/text/rich.rs
+++ b/src/text/rich.rs
@@ -40,8 +40,9 @@ pub struct Rich<
align_y: alignment::Vertical,
wrapping: Wrapping,
class: Theme::Class<'a>,
- hovered_link: Option<usize>,
on_link_click: Option<Box<dyn Fn(Link) -> Message + 'a>>,
+ on_link_hover: Option<Box<dyn Fn(Link) -> Message + 'a>>,
+ on_hover_lost: Option<Box<dyn Fn() -> Message + 'a>>,
}
impl<'a, Link, Message, Theme, Renderer>
@@ -65,8 +66,9 @@ where
align_y: alignment::Vertical::Top,
wrapping: Wrapping::default(),
class: Theme::default(),
- hovered_link: None,
on_link_click: None,
+ on_link_hover: None,
+ on_hover_lost: None,
}
}
@@ -147,6 +149,36 @@ where
self
}
+ /// Sets the message that will be produced when a link of the [`Rich`] text
+ /// is hovered.
+ pub fn on_link_hover(
+ mut self,
+ on_link_hovered: impl Fn(Link) -> Message + 'a,
+ ) -> Self {
+ self.on_link_hover = Some(Box::new(on_link_hovered));
+ self
+ }
+
+ /// Sets the message that will be produced when a link of the [`Rich`] text
+ /// is no longer hovered.
+ pub fn on_hover_lost(mut self, on_hover_lost: Message) -> Self
+ where
+ Message: Clone + 'a,
+ {
+ self.on_hover_lost = Some(Box::new(move || on_hover_lost.clone()));
+ self
+ }
+
+ /// Sets the message that will be produced when a link of the [`Rich`] text
+ /// is no longer hovered.
+ pub fn on_hover_lost_with(
+ mut self,
+ on_hover_lost: impl Fn() -> Message + 'a,
+ ) -> Self {
+ self.on_hover_lost = Some(Box::new(on_hover_lost));
+ self
+ }
+
/// Sets the default style of the [`Rich`] text.
#[must_use]
pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self
@@ -181,6 +213,7 @@ where
struct State<Link> {
spans: Vec<Span<'static, Link, Font>>,
span_pressed: Option<usize>,
+ hovered_link: Option<usize>,
paragraph: Paragraph,
is_hovered: bool,
selection: Selection,
@@ -335,6 +368,7 @@ where
tree::State::new(State::<Link> {
spans: Vec::new(),
span_pressed: None,
+ hovered_link: None,
paragraph: Paragraph::default(),
is_hovered: false,
selection: Selection::default(),
@@ -393,7 +427,7 @@ where
for (index, span) in self.spans.as_ref().as_ref().iter().enumerate() {
let is_hovered_link = self.on_link_click.is_some()
- && Some(index) == self.hovered_link;
+ && Some(index) == state.hovered_link;
if span.highlight.is_some()
|| span.underline
@@ -572,14 +606,14 @@ where
return;
}
- let link_was_hovered = self.hovered_link.is_some();
let was_hovered = state.is_hovered;
+ let hovered_link_before = state.hovered_link;
let selection_before = state.selection;
state.is_hovered = click_position.is_some();
if let Some(position) = click_position {
- self.hovered_link =
+ state.hovered_link =
state.paragraph.hit_span(position).and_then(|span| {
if self.spans.as_ref().as_ref().get(span)?.link.is_some() {
Some(span)
@@ -588,14 +622,14 @@ where
}
});
} else {
- self.hovered_link = None;
+ state.hovered_link = None;
}
match event {
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
| Event::Touch(touch::Event::FingerPressed { .. }) => {
- if self.hovered_link.is_some() {
- state.span_pressed = self.hovered_link;
+ if state.hovered_link.is_some() {
+ state.span_pressed = state.hovered_link;
shell.capture_event();
}
@@ -653,7 +687,7 @@ where
) && state.selection.is_empty()
{
match state.span_pressed {
- Some(span) if Some(span) == self.hovered_link => {
+ Some(span) if Some(span) == state.hovered_link => {
if let Some((link, on_link_clicked)) = self
.spans
.as_ref()
@@ -823,21 +857,38 @@ where
if state.is_hovered != was_hovered
|| state.selection != selection_before
- || self.hovered_link.is_some() != link_was_hovered
+ || state.hovered_link != hovered_link_before
{
+ if let Some(span) = state.hovered_link {
+ if let Some((link, on_link_hovered)) = self
+ .spans
+ .as_ref()
+ .as_ref()
+ .get(span)
+ .and_then(|span| span.link.clone())
+ .zip(self.on_link_hover.as_deref())
+ {
+ shell.publish(on_link_hovered(link));
+ }
+ } else if let Some(on_hover_lost) = self.on_hover_lost.as_deref() {
+ shell.publish(on_hover_lost());
+ }
+
shell.request_redraw();
}
}
fn mouse_interaction(
&self,
- _tree: &Tree,
+ tree: &Tree,
layout: Layout<'_>,
cursor: mouse::Cursor,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
- if self.hovered_link.is_some() {
+ let state = tree.state.downcast_ref::<State<Link>>();
+
+ if state.hovered_link.is_some() {
mouse::Interaction::Pointer
} else if cursor.is_over(layout.bounds()) {
mouse::Interaction::Text