Skip to content

Commit 7493b83

Browse files
committed
Fix rich_text reactive rendering when hovering links
1 parent eb81679 commit 7493b83

File tree

1 file changed

+52
-61
lines changed

1 file changed

+52
-61
lines changed

widget/src/text/rich.rs

+52-61
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ where
3030
align_y: alignment::Vertical,
3131
wrapping: Wrapping,
3232
class: Theme::Class<'a>,
33+
hovered_link: Option<usize>,
3334
}
3435

3536
impl<'a, Link, Theme, Renderer> Rich<'a, Link, Theme, Renderer>
@@ -52,6 +53,7 @@ where
5253
align_y: alignment::Vertical::Top,
5354
wrapping: Wrapping::default(),
5455
class: Theme::default(),
56+
hovered_link: None,
5557
}
5658
}
5759

@@ -236,7 +238,7 @@ where
236238
theme: &Theme,
237239
defaults: &renderer::Style,
238240
layout: Layout<'_>,
239-
cursor: mouse::Cursor,
241+
_cursor: mouse::Cursor,
240242
viewport: &Rectangle,
241243
) {
242244
if !layout.bounds().intersects(viewport) {
@@ -249,13 +251,8 @@ where
249251

250252
let style = theme.style(&self.class);
251253

252-
let hovered_span = cursor
253-
.position_in(layout.bounds())
254-
.and_then(|position| state.paragraph.hit_span(position));
255-
256254
for (index, span) in self.spans.as_ref().as_ref().iter().enumerate() {
257-
let is_hovered_link =
258-
span.link.is_some() && Some(index) == hovered_span;
255+
let is_hovered_link = Some(index) == self.hovered_link;
259256

260257
if span.highlight.is_some()
261258
|| span.underline
@@ -369,83 +366,77 @@ where
369366
shell: &mut Shell<'_, Link>,
370367
_viewport: &Rectangle,
371368
) {
369+
let was_hovered = self.hovered_link.is_some();
370+
371+
if let Some(position) = cursor.position_in(layout.bounds()) {
372+
let state = tree
373+
.state
374+
.downcast_ref::<State<Link, Renderer::Paragraph>>();
375+
376+
self.hovered_link =
377+
state.paragraph.hit_span(position).and_then(|span| {
378+
if self.spans.as_ref().as_ref().get(span)?.link.is_some() {
379+
Some(span)
380+
} else {
381+
None
382+
}
383+
});
384+
} else {
385+
self.hovered_link = None;
386+
}
387+
388+
if was_hovered != self.hovered_link.is_some() {
389+
shell.request_redraw();
390+
}
391+
372392
match event {
373393
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
374-
if let Some(position) = cursor.position_in(layout.bounds()) {
375-
let state = tree
376-
.state
377-
.downcast_mut::<State<Link, Renderer::Paragraph>>();
394+
let state = tree
395+
.state
396+
.downcast_mut::<State<Link, Renderer::Paragraph>>();
378397

379-
if let Some(span) = state.paragraph.hit_span(position) {
380-
if self
381-
.spans
382-
.as_ref()
383-
.as_ref()
384-
.get(span)
385-
.is_some_and(|span| span.link.is_some())
386-
{
387-
state.span_pressed = Some(span);
388-
shell.capture_event();
389-
}
390-
}
391-
}
398+
state.span_pressed = self.hovered_link;
399+
shell.capture_event();
392400
}
393401
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
394402
let state = tree
395403
.state
396404
.downcast_mut::<State<Link, Renderer::Paragraph>>();
397405

398-
if let Some(span_pressed) = state.span_pressed {
399-
state.span_pressed = None;
400-
401-
if let Some(position) = cursor.position_in(layout.bounds())
402-
{
403-
match state.paragraph.hit_span(position) {
404-
Some(span) if span == span_pressed => {
405-
if let Some(link) = self
406-
.spans
407-
.as_ref()
408-
.as_ref()
409-
.get(span)
410-
.and_then(|span| span.link.clone())
411-
{
412-
shell.publish(link);
413-
}
414-
}
415-
_ => {}
406+
match state.span_pressed {
407+
Some(span) if Some(span) == self.hovered_link => {
408+
if let Some(link) = self
409+
.spans
410+
.as_ref()
411+
.as_ref()
412+
.get(span)
413+
.and_then(|span| span.link.clone())
414+
{
415+
shell.publish(link);
416416
}
417417
}
418+
_ => {}
418419
}
420+
421+
state.span_pressed = None;
419422
}
420423
_ => {}
421424
}
422425
}
423426

424427
fn mouse_interaction(
425428
&self,
426-
tree: &Tree,
427-
layout: Layout<'_>,
428-
cursor: mouse::Cursor,
429+
_tree: &Tree,
430+
_layout: Layout<'_>,
431+
_cursor: mouse::Cursor,
429432
_viewport: &Rectangle,
430433
_renderer: &Renderer,
431434
) -> mouse::Interaction {
432-
if let Some(position) = cursor.position_in(layout.bounds()) {
433-
let state = tree
434-
.state
435-
.downcast_ref::<State<Link, Renderer::Paragraph>>();
436-
437-
if let Some(span) = state
438-
.paragraph
439-
.hit_span(position)
440-
.and_then(|span| self.spans.as_ref().as_ref().get(span))
441-
{
442-
if span.link.is_some() {
443-
return mouse::Interaction::Pointer;
444-
}
445-
}
435+
if self.hovered_link.is_some() {
436+
mouse::Interaction::Pointer
437+
} else {
438+
mouse::Interaction::None
446439
}
447-
448-
mouse::Interaction::None
449440
}
450441
}
451442

0 commit comments

Comments
 (0)