diff options
Diffstat (limited to 'native/src/widget/tooltip.rs')
-rw-r--r-- | native/src/widget/tooltip.rs | 186 |
1 files changed, 131 insertions, 55 deletions
diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs index 276afd41..c35005e0 100644 --- a/native/src/widget/tooltip.rs +++ b/native/src/widget/tooltip.rs @@ -3,28 +3,36 @@ use std::hash::Hash; use iced_core::Rectangle; +use crate::event; +use crate::layout; +use crate::mouse; +use crate::renderer; +use crate::text; use crate::widget::container; -use crate::widget::text::{self, Text}; +use crate::widget::text::Text; use crate::{ - event, layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, - Widget, + Clipboard, Element, Event, Hasher, Layout, Length, Padding, Point, Size, + Vector, Widget, }; /// An element to display a widget over another. #[allow(missing_debug_implementations)] -pub struct Tooltip<'a, Message, Renderer: self::Renderer> { +pub struct Tooltip<'a, Message, Renderer: text::Renderer> { content: Element<'a, Message, Renderer>, tooltip: Text<Renderer>, position: Position, - style: <Renderer as container::Renderer>::Style, + style_sheet: Box<dyn container::StyleSheet + 'a>, gap: u16, padding: u16, } impl<'a, Message, Renderer> Tooltip<'a, Message, Renderer> where - Renderer: self::Renderer, + Renderer: text::Renderer, { + /// The default padding of a [`Tooltip`] drawn by this renderer. + const DEFAULT_PADDING: u16 = 5; + /// Creates an empty [`Tooltip`]. /// /// [`Tooltip`]: struct.Tooltip.html @@ -37,9 +45,9 @@ where content: content.into(), tooltip: Text::new(tooltip.to_string()), position, - style: Default::default(), + style_sheet: Default::default(), gap: 0, - padding: Renderer::DEFAULT_PADDING, + padding: Self::DEFAULT_PADDING, } } @@ -72,9 +80,9 @@ where /// Sets the style of the [`Tooltip`]. pub fn style( mut self, - style: impl Into<<Renderer as container::Renderer>::Style>, + style_sheet: impl Into<Box<dyn container::StyleSheet + 'a>>, ) -> Self { - self.style = style.into(); + self.style_sheet = style_sheet.into(); self } } @@ -97,7 +105,7 @@ pub enum Position { impl<'a, Message, Renderer> Widget<Message, Renderer> for Tooltip<'a, Message, Renderer> where - Renderer: self::Renderer, + Renderer: text::Renderer, { fn width(&self) -> Length { self.content.width() @@ -134,27 +142,126 @@ where ) } + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + ) -> mouse::Interaction { + self.content + .mouse_interaction(layout, cursor_position, viewport) + } + fn draw( &self, renderer: &mut Renderer, - defaults: &Renderer::Defaults, + inherited_style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, - ) -> Renderer::Output { - self::Renderer::draw( + ) { + self.content.draw( renderer, - defaults, - cursor_position, + inherited_style, layout, + cursor_position, viewport, - &self.content, - &self.tooltip, - self.position, - &self.style, - self.gap, - self.padding, - ) + ); + + let bounds = layout.bounds(); + + if bounds.contains(cursor_position) { + let gap = f32::from(self.gap); + let style = self.style_sheet.style(); + + let defaults = renderer::Style { + text_color: style + .text_color + .unwrap_or(inherited_style.text_color), + }; + + let text_layout = Widget::<(), Renderer>::layout( + &self.tooltip, + renderer, + &layout::Limits::new(Size::ZERO, viewport.size()) + .pad(Padding::new(self.padding)), + ); + + let padding = f32::from(self.padding); + let text_bounds = text_layout.bounds(); + let x_center = bounds.x + (bounds.width - text_bounds.width) / 2.0; + let y_center = + bounds.y + (bounds.height - text_bounds.height) / 2.0; + + let mut tooltip_bounds = { + let offset = match self.position { + Position::Top => Vector::new( + x_center, + bounds.y - text_bounds.height - gap - padding, + ), + Position::Bottom => Vector::new( + x_center, + bounds.y + bounds.height + gap + padding, + ), + Position::Left => Vector::new( + bounds.x - text_bounds.width - gap - padding, + y_center, + ), + Position::Right => Vector::new( + bounds.x + bounds.width + gap + padding, + y_center, + ), + Position::FollowCursor => Vector::new( + cursor_position.x, + cursor_position.y - text_bounds.height, + ), + }; + + Rectangle { + x: offset.x - padding, + y: offset.y - padding, + width: text_bounds.width + padding * 2.0, + height: text_bounds.height + padding * 2.0, + } + }; + + if tooltip_bounds.x < viewport.x { + tooltip_bounds.x = viewport.x; + } else if viewport.x + viewport.width + < tooltip_bounds.x + tooltip_bounds.width + { + tooltip_bounds.x = + viewport.x + viewport.width - tooltip_bounds.width; + } + + if tooltip_bounds.y < viewport.y { + tooltip_bounds.y = viewport.y; + } else if viewport.y + viewport.height + < tooltip_bounds.y + tooltip_bounds.height + { + tooltip_bounds.y = + viewport.y + viewport.height - tooltip_bounds.height; + } + + renderer.with_layer(*viewport, |renderer| { + container::draw_background(renderer, &style, tooltip_bounds); + + Widget::<(), Renderer>::draw( + &self.tooltip, + renderer, + &defaults, + Layout::with_offset( + Vector::new( + tooltip_bounds.x + padding, + tooltip_bounds.y + padding, + ), + &text_layout, + ), + cursor_position, + viewport, + ); + }); + } } fn hash_layout(&self, state: &mut Hasher) { @@ -165,41 +272,10 @@ where } } -/// The renderer of a [`Tooltip`]. -/// -/// Your [renderer] will need to implement this trait before being -/// able to use a [`Tooltip`] in your user interface. -/// -/// [`Tooltip`]: struct.Tooltip.html -/// [renderer]: ../../renderer/index.html -pub trait Renderer: - crate::Renderer + text::Renderer + container::Renderer -{ - /// The default padding of a [`Tooltip`] drawn by this renderer. - const DEFAULT_PADDING: u16; - - /// Draws a [`Tooltip`]. - /// - /// [`Tooltip`]: struct.Tooltip.html - fn draw<Message>( - &mut self, - defaults: &Self::Defaults, - cursor_position: Point, - content_layout: Layout<'_>, - viewport: &Rectangle, - content: &Element<'_, Message, Self>, - tooltip: &Text<Self>, - position: Position, - style: &<Self as container::Renderer>::Style, - gap: u16, - padding: u16, - ) -> Self::Output; -} - impl<'a, Message, Renderer> From<Tooltip<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + self::Renderer, + Renderer: 'a + text::Renderer, Message: 'a, { fn from( |