Skip to content

Commit

Permalink
feat(native): add Tooltip widget
Browse files Browse the repository at this point in the history
  • Loading branch information
yusdacra committed Jan 18, 2021
1 parent 9da0a3d commit 061870a
Show file tree
Hide file tree
Showing 23 changed files with 580 additions and 18 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ members = [
"examples/svg",
"examples/todos",
"examples/tour",
"examples/tooltip",
]

[dependencies]
Expand Down
9 changes: 9 additions & 0 deletions examples/tooltip/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "tooltip"
version = "0.1.0"
authors = ["Yusuf Bera Ertan <y.bera003.06@protonmail.com>"]
edition = "2018"
publish = false

[dependencies]
iced = { path = "../..", features = ["debug"] }
14 changes: 14 additions & 0 deletions examples/tooltip/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Tooltip

A tooltip.

It displays and positions a widget on another based on cursor position.

The __[`main`]__ file contains all the code of the example.

You can run it with `cargo run`:
```
cargo run --package tooltip
```

[`main`]: src/main.rs
123 changes: 123 additions & 0 deletions examples/tooltip/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use iced::{
button, tooltip::TooltipPosition, Button, Column, Container, Element,
Length, Row, Sandbox, Settings, Text, Tooltip,
};

pub fn main() {
Example::run(Settings::default()).unwrap()
}

#[derive(Default)]
struct Example {
tooltip_top_button_state: button::State,
tooltip_bottom_button_state: button::State,
tooltip_right_button_state: button::State,
tooltip_left_button_state: button::State,
tooltip_cursor_button_state: button::State,
}

#[derive(Debug, Clone, Copy)]
struct Message;

impl Sandbox for Example {
type Message = Message;

fn new() -> Self {
Self::default()
}

fn title(&self) -> String {
String::from("Tooltip - Iced")
}

fn update(&mut self, _message: Message) {}

fn view(&mut self) -> Element<Message> {
let tooltip_top = tooltip_builder(
"Tooltip at top",
&mut self.tooltip_top_button_state,
TooltipPosition::Top,
);
let tooltip_bottom = tooltip_builder(
"Tooltip at bottom",
&mut self.tooltip_bottom_button_state,
TooltipPosition::Bottom,
);
let tooltip_right = tooltip_builder(
"Tooltip at right",
&mut self.tooltip_right_button_state,
TooltipPosition::Right,
);
let tooltip_left = tooltip_builder(
"Tooltip at left",
&mut self.tooltip_left_button_state,
TooltipPosition::Left,
);

let fixed_tooltips = Row::with_children(vec![
tooltip_top.into(),
tooltip_bottom.into(),
tooltip_left.into(),
tooltip_right.into(),
])
.width(Length::Fill)
.height(Length::Fill)
.align_items(iced::Align::Center)
.spacing(120);

let cursor_tooltip_area = Tooltip::new(
Button::new(
&mut self.tooltip_cursor_button_state,
Container::new(Text::new("Tooltip follows cursor").size(40))
.center_y()
.center_x()
.width(Length::Fill)
.height(Length::Fill),
)
.on_press(Message)
.width(Length::Fill)
.height(Length::Fill),
tooltip(),
TooltipPosition::FollowCursor,
);

let content = Column::with_children(vec![
Container::new(fixed_tooltips)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into(),
cursor_tooltip_area.into(),
])
.width(Length::Fill)
.height(Length::Fill);

Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}

fn tooltip_builder<'a>(
label: &str,
button_state: &'a mut button::State,
position: TooltipPosition,
) -> Container<'a, Message> {
Container::new(Tooltip::new(
Button::new(button_state, Text::new(label).size(40)).on_press(Message),
tooltip(),
position,
))
.center_x()
.center_y()
.width(Length::Fill)
.height(Length::Fill)
}

fn tooltip() -> Text {
Text::new("Tooltip").size(20)
}
3 changes: 3 additions & 0 deletions graphics/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub mod scrollable;
pub mod slider;
pub mod svg;
pub mod text_input;
pub mod tooltip;

mod column;
mod row;
Expand Down Expand Up @@ -48,6 +49,8 @@ pub use scrollable::Scrollable;
pub use slider::Slider;
#[doc(no_inline)]
pub use text_input::TextInput;
#[doc(no_inline)]
pub use tooltip::Tooltip;

pub use column::Column;
pub use image::Image;
Expand Down
37 changes: 37 additions & 0 deletions graphics/src/widget/tooltip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Decorate content and apply alignment.
use crate::defaults::Defaults;
use crate::{Backend, Renderer};
use iced_native::{Element, Layout, Point, Rectangle};

/// An element decorating some content.
///
/// This is an alias of an `iced_native` tooltip with a default
/// `Renderer`.
pub type Tooltip<'a, Message, Backend> =
iced_native::Tooltip<'a, Message, Renderer<Backend>>;

impl<B> iced_native::tooltip::Renderer for Renderer<B>
where
B: Backend,
{
type Style = ();

fn draw<Message>(
&mut self,
defaults: &Defaults,
cursor_position: Point,
content: &Element<'_, Message, Self>,
content_layout: Layout<'_>,
viewport: &Rectangle,
) -> Self::Output {
let (content, mouse_interaction) = content.draw(
self,
&defaults,
content_layout,
cursor_position,
viewport,
);

(content, mouse_interaction)
}
}
14 changes: 11 additions & 3 deletions native/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,11 @@ where
pub fn overlay<'b>(
&'b mut self,
layout: Layout<'_>,
overlay_content_bounds: Option<Rectangle>,
cursor_position: Point,
) -> Option<overlay::Element<'b, Message, Renderer>> {
self.widget.overlay(layout)
self.widget
.overlay(layout, overlay_content_bounds, cursor_position)
}
}

Expand Down Expand Up @@ -352,11 +355,13 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
overlay_content_bounds: Option<Rectangle>,
cursor_position: Point,
) -> Option<overlay::Element<'_, B, Renderer>> {
let mapper = &self.mapper;

self.widget
.overlay(layout)
.overlay(layout, overlay_content_bounds, cursor_position)
.map(move |overlay| overlay.map(mapper))
}
}
Expand Down Expand Up @@ -440,7 +445,10 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
overlay_content_bounds: Option<Rectangle>,
cursor_position: Point,
) -> Option<overlay::Element<'_, Message, Renderer>> {
self.element.overlay(layout)
self.element
.overlay(layout, overlay_content_bounds, cursor_position)
}
}
2 changes: 2 additions & 0 deletions native/src/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod element;
pub mod menu;

pub use element::Element;
use iced_core::Rectangle;
pub use menu::Menu;

use crate::event::{self, Event};
Expand Down Expand Up @@ -35,6 +36,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) -> Renderer::Output;

/// Computes the _layout_ hash of the [`Overlay`].
Expand Down
8 changes: 6 additions & 2 deletions native/src/overlay/element.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use iced_core::Rectangle;

pub use crate::Overlay;

use crate::event::{self, Event};
Expand Down Expand Up @@ -74,9 +76,10 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) -> Renderer::Output {
self.overlay
.draw(renderer, defaults, layout, cursor_position)
.draw(renderer, defaults, layout, cursor_position, viewport)
}

/// Computes the _layout_ hash of the [`Element`].
Expand Down Expand Up @@ -145,9 +148,10 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
viewport: &Rectangle,
) -> Renderer::Output {
self.content
.draw(renderer, defaults, layout, cursor_position)
.draw(renderer, defaults, layout, cursor_position, viewport)
}

fn hash_layout(&self, state: &mut Hasher, position: Point) {
Expand Down
1 change: 1 addition & 0 deletions native/src/overlay/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ where
defaults: &Renderer::Defaults,
layout: Layout<'_>,
cursor_position: Point,
_viewport: &Rectangle,
) -> Renderer::Output {
let primitives = self.container.draw(
renderer,
Expand Down
16 changes: 11 additions & 5 deletions native/src/user_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,11 @@ where
messages: &mut Vec<Message>,
) -> Vec<event::Status> {
let (base_cursor, overlay_statuses) = if let Some(mut overlay) =
self.root.overlay(Layout::new(&self.base.layout))
{
self.root.overlay(
Layout::new(&self.base.layout),
self.overlay.as_ref().map(|l| l.layout.bounds()),
cursor_position,
) {
let layer = Self::overlay_layer(
self.overlay.take(),
self.bounds,
Expand Down Expand Up @@ -334,9 +337,11 @@ where
) -> Renderer::Output {
let viewport = Rectangle::with_size(self.bounds);

let overlay = if let Some(mut overlay) =
self.root.overlay(Layout::new(&self.base.layout))
{
let overlay = if let Some(mut overlay) = self.root.overlay(
Layout::new(&self.base.layout),
self.overlay.as_ref().map(|l| l.layout.bounds()),
cursor_position,
) {
let layer = Self::overlay_layer(
self.overlay.take(),
self.bounds,
Expand All @@ -351,6 +356,7 @@ where
&Renderer::Defaults::default(),
Layout::new(&layer.layout),
cursor_position,
&viewport,
);

self.overlay = Some(layer);
Expand Down
5 changes: 5 additions & 0 deletions native/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub mod space;
pub mod svg;
pub mod text;
pub mod text_input;
pub mod tooltip;

#[doc(no_inline)]
pub use button::Button;
Expand Down Expand Up @@ -71,6 +72,8 @@ pub use svg::Svg;
pub use text::Text;
#[doc(no_inline)]
pub use text_input::TextInput;
#[doc(no_inline)]
pub use tooltip::Tooltip;

use crate::event::{self, Event};
use crate::layout;
Expand Down Expand Up @@ -172,6 +175,8 @@ where
fn overlay(
&mut self,
_layout: Layout<'_>,
_overlay_content_bounds: Option<Rectangle>,
_cursor_position: Point,
) -> Option<overlay::Element<'_, Message, Renderer>> {
None
}
Expand Down
10 changes: 9 additions & 1 deletion native/src/widget/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,19 @@ where
fn overlay(
&mut self,
layout: Layout<'_>,
overlay_content_bounds: Option<Rectangle>,
cursor_position: Point,
) -> Option<overlay::Element<'_, Message, Renderer>> {
self.children
.iter_mut()
.zip(layout.children())
.filter_map(|(child, layout)| child.widget.overlay(layout))
.filter_map(|(child, layout)| {
child.widget.overlay(
layout,
overlay_content_bounds,
cursor_position,
)
})
.next()
}
}
Expand Down
Loading

0 comments on commit 061870a

Please sign in to comment.