summaryrefslogtreecommitdiffstats
path: root/widget/src/text
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/src/text/rich.rs117
-rw-r--r--widget/src/text_editor.rs36
2 files changed, 87 insertions, 66 deletions
diff --git a/widget/src/text/rich.rs b/widget/src/text/rich.rs
index a40f2b57..0b499ec6 100644
--- a/widget/src/text/rich.rs
+++ b/widget/src/text/rich.rs
@@ -30,6 +30,7 @@ where
align_y: alignment::Vertical,
wrapping: Wrapping,
class: Theme::Class<'a>,
+ hovered_link: Option<usize>,
}
impl<'a, Link, Theme, Renderer> Rich<'a, Link, Theme, Renderer>
@@ -52,6 +53,7 @@ where
align_y: alignment::Vertical::Top,
wrapping: Wrapping::default(),
class: Theme::default(),
+ hovered_link: None,
}
}
@@ -236,22 +238,21 @@ where
theme: &Theme,
defaults: &renderer::Style,
layout: Layout<'_>,
- cursor: mouse::Cursor,
+ _cursor: mouse::Cursor,
viewport: &Rectangle,
) {
+ if !layout.bounds().intersects(viewport) {
+ return;
+ }
+
let state = tree
.state
.downcast_ref::<State<Link, Renderer::Paragraph>>();
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.as_ref().as_ref().iter().enumerate() {
- let is_hovered_link =
- span.link.is_some() && Some(index) == hovered_span;
+ let is_hovered_link = Some(index) == self.hovered_link;
if span.highlight.is_some()
|| span.underline
@@ -365,25 +366,38 @@ where
shell: &mut Shell<'_, Link>,
_viewport: &Rectangle,
) {
+ let was_hovered = self.hovered_link.is_some();
+
+ if let Some(position) = cursor.position_in(layout.bounds()) {
+ let state = tree
+ .state
+ .downcast_ref::<State<Link, Renderer::Paragraph>>();
+
+ self.hovered_link =
+ state.paragraph.hit_span(position).and_then(|span| {
+ if self.spans.as_ref().as_ref().get(span)?.link.is_some() {
+ Some(span)
+ } else {
+ None
+ }
+ });
+ } else {
+ self.hovered_link = None;
+ }
+
+ if was_hovered != self.hovered_link.is_some() {
+ shell.request_redraw();
+ }
+
match event {
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
- if let Some(position) = cursor.position_in(layout.bounds()) {
- let state = tree
- .state
- .downcast_mut::<State<Link, Renderer::Paragraph>>();
+ let state = tree
+ .state
+ .downcast_mut::<State<Link, Renderer::Paragraph>>();
- if let Some(span) = state.paragraph.hit_span(position) {
- if self
- .spans
- .as_ref()
- .as_ref()
- .get(span)
- .is_some_and(|span| span.link.is_some())
- {
- state.span_pressed = Some(span);
- shell.capture_event();
- }
- }
+ if self.hovered_link.is_some() {
+ state.span_pressed = self.hovered_link;
+ shell.capture_event();
}
}
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
@@ -391,27 +405,22 @@ where
.state
.downcast_mut::<State<Link, Renderer::Paragraph>>();
- if let Some(span_pressed) = state.span_pressed {
- state.span_pressed = None;
-
- if let Some(position) = cursor.position_in(layout.bounds())
- {
- match state.paragraph.hit_span(position) {
- Some(span) if span == span_pressed => {
- if let Some(link) = self
- .spans
- .as_ref()
- .as_ref()
- .get(span)
- .and_then(|span| span.link.clone())
- {
- shell.publish(link);
- }
- }
- _ => {}
+ match state.span_pressed {
+ Some(span) if Some(span) == self.hovered_link => {
+ if let Some(link) = self
+ .spans
+ .as_ref()
+ .as_ref()
+ .get(span)
+ .and_then(|span| span.link.clone())
+ {
+ shell.publish(link);
}
}
+ _ => {}
}
+
+ state.span_pressed = None;
}
_ => {}
}
@@ -419,29 +428,17 @@ where
fn mouse_interaction(
&self,
- tree: &Tree,
- layout: Layout<'_>,
- cursor: mouse::Cursor,
+ _tree: &Tree,
+ _layout: Layout<'_>,
+ _cursor: mouse::Cursor,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
- if let Some(position) = cursor.position_in(layout.bounds()) {
- let state = tree
- .state
- .downcast_ref::<State<Link, Renderer::Paragraph>>();
-
- if let Some(span) = state
- .paragraph
- .hit_span(position)
- .and_then(|span| self.spans.as_ref().as_ref().get(span))
- {
- if span.link.is_some() {
- return mouse::Interaction::Pointer;
- }
- }
+ if self.hovered_link.is_some() {
+ mouse::Interaction::Pointer
+ } else {
+ mouse::Interaction::None
}
-
- mouse::Interaction::None
}
}
diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs
index a3470768..f1ec589b 100644
--- a/widget/src/text_editor.rs
+++ b/widget/src/text_editor.rs
@@ -110,6 +110,8 @@ pub struct TextEditor<
line_height: LineHeight,
width: Length,
height: Length,
+ min_height: f32,
+ max_height: f32,
padding: Padding,
wrapping: Wrapping,
class: Theme::Class<'a>,
@@ -139,6 +141,8 @@ where
line_height: LineHeight::default(),
width: Length::Fill,
height: Length::Shrink,
+ min_height: 0.0,
+ max_height: f32::INFINITY,
padding: Padding::new(5.0),
wrapping: Wrapping::default(),
class: Theme::default(),
@@ -169,15 +173,27 @@ where
self
}
+ /// Sets the width of the [`TextEditor`].
+ pub fn width(mut self, width: impl Into<Pixels>) -> Self {
+ self.width = Length::from(width.into());
+ self
+ }
+
/// Sets the height of the [`TextEditor`].
pub fn height(mut self, height: impl Into<Length>) -> Self {
self.height = height.into();
self
}
- /// Sets the width of the [`TextEditor`].
- pub fn width(mut self, width: impl Into<Pixels>) -> Self {
- self.width = Length::from(width.into());
+ /// Sets the minimum height of the [`TextEditor`].
+ pub fn min_height(mut self, min_height: impl Into<Pixels>) -> Self {
+ self.min_height = min_height.into().0;
+ self
+ }
+
+ /// Sets the maximum height of the [`TextEditor`].
+ pub fn max_height(mut self, max_height: impl Into<Pixels>) -> Self {
+ self.max_height = max_height.into().0;
self
}
@@ -265,6 +281,8 @@ where
line_height: self.line_height,
width: self.width,
height: self.height,
+ min_height: self.min_height,
+ max_height: self.max_height,
padding: self.padding,
wrapping: self.wrapping,
class: self.class,
@@ -549,7 +567,11 @@ where
state.highlighter_settings = self.highlighter_settings.clone();
}
- let limits = limits.width(self.width).height(self.height);
+ let limits = limits
+ .width(self.width)
+ .height(self.height)
+ .min_height(self.min_height)
+ .max_height(self.max_height);
internal.editor.update(
limits.shrink(self.padding).max(),
@@ -768,6 +790,10 @@ where
}
}
+ if !matches!(binding, Binding::Unfocus) {
+ shell.capture_event();
+ }
+
apply_binding(
binding,
self.content,
@@ -780,8 +806,6 @@ where
if let Some(focus) = &mut state.focus {
focus.updated_at = Instant::now();
}
-
- shell.capture_event();
}
}
}