diff --git a/examples/tooltip/src/main.rs b/examples/tooltip/src/main.rs index 3677dc75..b10b8b50 100644 --- a/examples/tooltip/src/main.rs +++ b/examples/tooltip/src/main.rs @@ -114,5 +114,25 @@ fn tooltip<'a>( position, ) .gap(10) + .padding(20) + .style(style::Tooltip) .into() } + +mod style { + use iced::container; + use iced::Color; + + pub struct Tooltip; + + impl container::StyleSheet for Tooltip { + fn style(&self) -> container::Style { + container::Style { + text_color: Some(Color::from_rgb8(0xEE, 0xEE, 0xEE)), + background: Some(Color::from_rgb(0.11, 0.42, 0.87).into()), + border_radius: 12.0, + ..container::Style::default() + } + } + } +} diff --git a/graphics/src/widget/tooltip.rs b/graphics/src/widget/tooltip.rs index 26b18507..51b465a5 100644 --- a/graphics/src/widget/tooltip.rs +++ b/graphics/src/widget/tooltip.rs @@ -1,8 +1,9 @@ //! Decorate content and apply alignment. use crate::backend::{self, Backend}; -use crate::defaults::Defaults; +use crate::defaults::{self, Defaults}; use crate::{Primitive, Renderer, Vector}; +use iced_native::container; use iced_native::layout::{self, Layout}; use iced_native::{Element, Point, Rectangle, Size, Text}; @@ -19,7 +20,7 @@ impl iced_native::tooltip::Renderer for Renderer where B: Backend + backend::Text, { - type Style = (); + const DEFAULT_PADDING: u16 = 5; fn draw( &mut self, @@ -30,10 +31,10 @@ where content: &Element<'_, Message, Self>, tooltip: &Text, position: Position, + style_sheet: &::Style, gap: u16, + padding: u16, ) -> Self::Output { - let bounds = content_layout.bounds(); - let (content, mouse_interaction) = content.draw( self, &defaults, @@ -42,13 +43,26 @@ where viewport, ); + let bounds = content_layout.bounds(); + if bounds.contains(cursor_position) { use iced_native::Widget; + let gap = f32::from(gap); + let padding = f32::from(padding); + let style = style_sheet.style(); + + let defaults = Defaults { + text: defaults::Text { + color: style.text_color.unwrap_or(defaults.text.color), + }, + }; + let tooltip_layout = Widget::<(), Self>::layout( tooltip, self, - &layout::Limits::new(Size::ZERO, viewport.size()), + &layout::Limits::new(Size::ZERO, viewport.size()) + .pad(f32::from(padding)), ); let tooltip_bounds = tooltip_layout.bounds(); @@ -59,22 +73,23 @@ where let y_center = bounds.y + (bounds.height - tooltip_bounds.height) / 2.0; - let gap = f32::from(gap); - let offset = match position { Position::Top => Vector::new( x_center, - bounds.y - tooltip_bounds.height - gap, + bounds.y - tooltip_bounds.height - gap - padding, + ), + Position::Bottom => Vector::new( + x_center, + bounds.y + bounds.height + gap + padding, + ), + Position::Left => Vector::new( + bounds.x - tooltip_bounds.width - gap - padding, + y_center, + ), + Position::Right => Vector::new( + bounds.x + bounds.width + gap + padding, + y_center, ), - Position::Bottom => { - Vector::new(x_center, bounds.y + bounds.height + gap) - } - Position::Left => { - Vector::new(bounds.x - tooltip_bounds.width - gap, y_center) - } - Position::Right => { - Vector::new(bounds.x + bounds.width + gap, y_center) - } Position::FollowCursor => Vector::new( cursor_position.x, cursor_position.y - tooltip_bounds.height, @@ -84,19 +99,42 @@ where let (tooltip, _) = Widget::<(), Self>::draw( tooltip, self, - defaults, + &defaults, Layout::with_offset(offset, &tooltip_layout), cursor_position, viewport, ); + let tooltip_bounds = Rectangle { + x: offset.x - padding, + y: offset.y - padding, + width: tooltip_bounds.width + padding * 2.0, + height: tooltip_bounds.height + padding * 2.0, + }; + ( - Primitive::Clip { - bounds: *viewport, - offset: Vector::new(0, 0), - content: Box::new(Primitive::Group { - primitives: vec![content, tooltip], - }), + Primitive::Group { + primitives: vec![ + content, + Primitive::Clip { + bounds: *viewport, + offset: Vector::new(0, 0), + content: Box::new( + if let Some(background) = + crate::container::background( + tooltip_bounds, + &style, + ) + { + Primitive::Group { + primitives: vec![background, tooltip], + } + } else { + tooltip + }, + ), + }, + ], }, mouse_interaction, ) diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs index 6da7b0ca..56559827 100644 --- a/native/src/widget/tooltip.rs +++ b/native/src/widget/tooltip.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use iced_core::Rectangle; +use crate::widget::container; use crate::widget::text::{self, Text}; use crate::{ event, layout, Clipboard, Element, Event, Hasher, Layout, Length, Point, @@ -11,16 +12,18 @@ use crate::{ /// An element to display a widget over another. #[allow(missing_debug_implementations)] -pub struct Tooltip<'a, Message, Renderer: self::Renderer + text::Renderer> { +pub struct Tooltip<'a, Message, Renderer: self::Renderer> { content: Element<'a, Message, Renderer>, tooltip: Text, position: Position, + style: ::Style, gap: u16, + padding: u16, } impl<'a, Message, Renderer> Tooltip<'a, Message, Renderer> where - Renderer: self::Renderer + text::Renderer, + Renderer: self::Renderer, { /// Creates an empty [`Tooltip`]. /// @@ -34,15 +37,32 @@ where content: content.into(), tooltip, position, + style: Default::default(), gap: 0, + padding: Renderer::DEFAULT_PADDING, } } + /// Sets the style of the [`Tooltip`]. + pub fn style( + mut self, + style: impl Into<::Style>, + ) -> Self { + self.style = style.into(); + self + } + /// Sets the gap between the content and its [`Tooltip`]. pub fn gap(mut self, gap: u16) -> Self { self.gap = gap; self } + + /// Sets the padding of the [`Tooltip`]. + pub fn padding(mut self, padding: u16) -> Self { + self.padding = padding; + self + } } /// The position of the tooltip. Defaults to following the cursor. @@ -63,7 +83,7 @@ pub enum Position { impl<'a, Message, Renderer> Widget for Tooltip<'a, Message, Renderer> where - Renderer: self::Renderer + text::Renderer, + Renderer: self::Renderer, { fn width(&self) -> Length { self.content.width() @@ -117,7 +137,9 @@ where &self.content, &self.tooltip, self.position, + &self.style, self.gap, + self.padding, ) } @@ -136,9 +158,11 @@ where /// /// [`Tooltip`]: struct.Tooltip.html /// [renderer]: ../../renderer/index.html -pub trait Renderer: crate::Renderer + text::Renderer { - /// The style supported by this renderer. - type Style: Default; +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`]. /// @@ -152,14 +176,16 @@ pub trait Renderer: crate::Renderer + text::Renderer { content: &Element<'_, Message, Self>, tooltip: &Text, position: Position, + style: &::Style, gap: u16, + padding: u16, ) -> Self::Output; } impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where - Renderer: 'a + self::Renderer + text::Renderer, + Renderer: 'a + self::Renderer, Message: 'a, { fn from(