diff options
Diffstat (limited to '')
-rw-r--r-- | widget/src/text/rich.rs | 117 | ||||
-rw-r--r-- | widget/src/text_editor.rs | 36 |
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(); } } } |