summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--examples/tooltip/Cargo.toml9
-rw-r--r--examples/tooltip/README.md14
-rw-r--r--examples/tooltip/src/main.rs138
-rw-r--r--glow/src/widget.rs3
-rw-r--r--glow/src/widget/tooltip.rs6
-rw-r--r--graphics/src/layer.rs40
-rw-r--r--graphics/src/widget.rs3
-rw-r--r--graphics/src/widget/tooltip.rs145
-rw-r--r--native/src/layout.rs7
-rw-r--r--native/src/widget.rs3
-rw-r--r--native/src/widget/tooltip.rs210
-rw-r--r--src/widget.rs5
-rw-r--r--wgpu/src/widget.rs3
-rw-r--r--wgpu/src/widget/tooltip.rs6
15 files changed, 577 insertions, 16 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 75499df9..f3a9676f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -83,6 +83,7 @@ members = [
"examples/svg",
"examples/todos",
"examples/tour",
+ "examples/tooltip",
]
[dependencies]
diff --git a/examples/tooltip/Cargo.toml b/examples/tooltip/Cargo.toml
new file mode 100644
index 00000000..1171de00
--- /dev/null
+++ b/examples/tooltip/Cargo.toml
@@ -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"] }
diff --git a/examples/tooltip/README.md b/examples/tooltip/README.md
new file mode 100644
index 00000000..4ccf6578
--- /dev/null
+++ b/examples/tooltip/README.md
@@ -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
diff --git a/examples/tooltip/src/main.rs b/examples/tooltip/src/main.rs
new file mode 100644
index 00000000..d6c8b8e1
--- /dev/null
+++ b/examples/tooltip/src/main.rs
@@ -0,0 +1,138 @@
+use iced::tooltip::{self, Tooltip};
+use iced::{
+ button, Button, Column, Container, Element, HorizontalAlignment, Length,
+ Row, Sandbox, Settings, Text, VerticalAlignment,
+};
+
+pub fn main() {
+ Example::run(Settings::default()).unwrap()
+}
+
+#[derive(Default)]
+struct Example {
+ top: button::State,
+ bottom: button::State,
+ right: button::State,
+ left: button::State,
+ follow_cursor: 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 top =
+ tooltip("Tooltip at top", &mut self.top, tooltip::Position::Top);
+
+ let bottom = tooltip(
+ "Tooltip at bottom",
+ &mut self.bottom,
+ tooltip::Position::Bottom,
+ );
+
+ let left =
+ tooltip("Tooltip at left", &mut self.left, tooltip::Position::Left);
+
+ let right = tooltip(
+ "Tooltip at right",
+ &mut self.right,
+ tooltip::Position::Right,
+ );
+
+ let fixed_tooltips = Row::with_children(vec![
+ top.into(),
+ bottom.into(),
+ left.into(),
+ right.into(),
+ ])
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .align_items(iced::Align::Center)
+ .spacing(50);
+
+ let follow_cursor = tooltip(
+ "Tooltip follows cursor",
+ &mut self.follow_cursor,
+ tooltip::Position::FollowCursor,
+ );
+
+ let content = Column::with_children(vec![
+ Container::new(fixed_tooltips)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y()
+ .into(),
+ follow_cursor.into(),
+ ])
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .spacing(50);
+
+ Container::new(content)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y()
+ .padding(50)
+ .into()
+ }
+}
+
+fn tooltip<'a>(
+ label: &str,
+ button_state: &'a mut button::State,
+ position: tooltip::Position,
+) -> Element<'a, Message> {
+ Tooltip::new(
+ Button::new(
+ button_state,
+ Text::new(label)
+ .size(40)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .horizontal_alignment(HorizontalAlignment::Center)
+ .vertical_alignment(VerticalAlignment::Center),
+ )
+ .on_press(Message)
+ .width(Length::Fill)
+ .height(Length::Fill),
+ "Tooltip",
+ position,
+ )
+ .gap(5)
+ .padding(10)
+ .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/glow/src/widget.rs b/glow/src/widget.rs
index b5c84c56..5481216a 100644
--- a/glow/src/widget.rs
+++ b/glow/src/widget.rs
@@ -20,6 +20,7 @@ pub mod rule;
pub mod scrollable;
pub mod slider;
pub mod text_input;
+pub mod tooltip;
#[doc(no_inline)]
pub use button::Button;
@@ -43,6 +44,8 @@ pub use scrollable::Scrollable;
pub use slider::Slider;
#[doc(no_inline)]
pub use text_input::TextInput;
+#[doc(no_inline)]
+pub use tooltip::Tooltip;
#[cfg(feature = "canvas")]
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
diff --git a/glow/src/widget/tooltip.rs b/glow/src/widget/tooltip.rs
new file mode 100644
index 00000000..89ab3a15
--- /dev/null
+++ b/glow/src/widget/tooltip.rs
@@ -0,0 +1,6 @@
+//! Display a widget over another.
+/// A widget allowing the selection of a single value from a list of options.
+pub type Tooltip<'a, Message> =
+ iced_native::Tooltip<'a, Message, crate::Renderer>;
+
+pub use iced_native::tooltip::Position;
diff --git a/graphics/src/layer.rs b/graphics/src/layer.rs
index ab40b114..7dce1d4c 100644
--- a/graphics/src/layer.rs
+++ b/graphics/src/layer.rs
@@ -82,7 +82,12 @@ impl<'a> Layer<'a> {
let mut layers = vec![first_layer];
- Self::process_primitive(&mut layers, Vector::new(0.0, 0.0), primitive);
+ Self::process_primitive(
+ &mut layers,
+ Vector::new(0.0, 0.0),
+ primitive,
+ 0,
+ );
layers
}
@@ -91,13 +96,19 @@ impl<'a> Layer<'a> {
layers: &mut Vec<Self>,
translation: Vector,
primitive: &'a Primitive,
+ current_layer: usize,
) {
match primitive {
Primitive::None => {}
Primitive::Group { primitives } => {
// TODO: Inspect a bit and regroup (?)
for primitive in primitives {
- Self::process_primitive(layers, translation, primitive)
+ Self::process_primitive(
+ layers,
+ translation,
+ primitive,
+ current_layer,
+ )
}
}
Primitive::Text {
@@ -109,7 +120,7 @@ impl<'a> Layer<'a> {
horizontal_alignment,
vertical_alignment,
} => {
- let layer = layers.last_mut().unwrap();
+ let layer = &mut layers[current_layer];
layer.text.push(Text {
content,
@@ -128,7 +139,7 @@ impl<'a> Layer<'a> {
border_width,
border_color,
} => {
- let layer = layers.last_mut().unwrap();
+ let layer = &mut layers[current_layer];
// TODO: Move some of these computations to the GPU (?)
layer.quads.push(Quad {
@@ -146,7 +157,7 @@ impl<'a> Layer<'a> {
});
}
Primitive::Mesh2D { buffers, size } => {
- let layer = layers.last_mut().unwrap();
+ let layer = &mut layers[current_layer];
let bounds = Rectangle::new(
Point::new(translation.x, translation.y),
@@ -167,7 +178,7 @@ impl<'a> Layer<'a> {
offset,
content,
} => {
- let layer = layers.last_mut().unwrap();
+ let layer = &mut layers[current_layer];
let translated_bounds = *bounds + translation;
// Only draw visible content
@@ -175,16 +186,15 @@ impl<'a> Layer<'a> {
layer.bounds.intersection(&translated_bounds)
{
let clip_layer = Layer::new(clip_bounds);
- let new_layer = Layer::new(layer.bounds);
-
layers.push(clip_layer);
+
Self::process_primitive(
layers,
translation
- Vector::new(offset.x as f32, offset.y as f32),
content,
+ layers.len() - 1,
);
- layers.push(new_layer);
}
}
Primitive::Translate {
@@ -195,13 +205,19 @@ impl<'a> Layer<'a> {
layers,
translation + *new_translation,
&content,
+ current_layer,
);
}
Primitive::Cached { cache } => {
- Self::process_primitive(layers, translation, &cache);
+ Self::process_primitive(
+ layers,
+ translation,
+ &cache,
+ current_layer,
+ );
}
Primitive::Image { handle, bounds } => {
- let layer = layers.last_mut().unwrap();
+ let layer = &mut layers[current_layer];
layer.images.push(Image::Raster {
handle: handle.clone(),
@@ -209,7 +225,7 @@ impl<'a> Layer<'a> {
});
}
Primitive::Svg { handle, bounds } => {
- let layer = layers.last_mut().unwrap();
+ let layer = &mut layers[current_layer];
layer.images.push(Image::Vector {
handle: handle.clone(),
diff --git a/graphics/src/widget.rs b/graphics/src/widget.rs
index 159ca91b..190ea9c0 100644
--- a/graphics/src/widget.rs
+++ b/graphics/src/widget.rs
@@ -20,6 +20,7 @@ pub mod scrollable;
pub mod slider;
pub mod svg;
pub mod text_input;
+pub mod tooltip;
mod column;
mod row;
@@ -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;
diff --git a/graphics/src/widget/tooltip.rs b/graphics/src/widget/tooltip.rs
new file mode 100644
index 00000000..51b465a5
--- /dev/null
+++ b/graphics/src/widget/tooltip.rs
@@ -0,0 +1,145 @@
+//! Decorate content and apply alignment.
+use crate::backend::{self, Backend};
+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};
+
+/// 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>>;
+
+pub use iced_native::tooltip::Position;
+
+impl<B> iced_native::tooltip::Renderer for Renderer<B>
+where
+ B: Backend + backend::Text,
+{
+ const DEFAULT_PADDING: u16 = 5;
+
+ fn draw<Message>(
+ &mut self,
+ defaults: &Defaults,
+ cursor_position: Point,
+ content_layout: Layout<'_>,
+ viewport: &Rectangle,
+ content: &Element<'_, Message, Self>,
+ tooltip: &Text<Self>,
+ position: Position,
+ style_sheet: &<Self as container::Renderer>::Style,
+ gap: u16,
+ padding: u16,
+ ) -> Self::Output {
+ let (content, mouse_interaction) = content.draw(
+ self,
+ &defaults,
+ content_layout,
+ cursor_position,
+ 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())
+ .pad(f32::from(padding)),
+ );
+
+ let tooltip_bounds = tooltip_layout.bounds();
+
+ let x_center =
+ bounds.x + (bounds.width - tooltip_bounds.width) / 2.0;
+
+ let y_center =
+ bounds.y + (bounds.height - tooltip_bounds.height) / 2.0;
+
+ let offset = match position {
+ Position::Top => Vector::new(
+ x_center,
+ 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::FollowCursor => Vector::new(
+ cursor_position.x,
+ cursor_position.y - tooltip_bounds.height,
+ ),
+ };
+
+ let (tooltip, _) = Widget::<(), Self>::draw(
+ tooltip,
+ self,
+ &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::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,
+ )
+ } else {
+ (content, mouse_interaction)
+ }
+ }
+}
diff --git a/native/src/layout.rs b/native/src/layout.rs
index 6d144902..b4b4a021 100644
--- a/native/src/layout.rs
+++ b/native/src/layout.rs
@@ -19,11 +19,14 @@ pub struct Layout<'a> {
}
impl<'a> Layout<'a> {
- pub(crate) fn new(node: &'a Node) -> Self {
+ /// Creates a new [`Layout`] for the given [`Node`] at the origin.
+ pub fn new(node: &'a Node) -> Self {
Self::with_offset(Vector::new(0.0, 0.0), node)
}
- pub(crate) fn with_offset(offset: Vector, node: &'a Node) -> Self {
+ /// Creates a new [`Layout`] for the given [`Node`] with the provided offset
+ /// from the origin.
+ pub fn with_offset(offset: Vector, node: &'a Node) -> Self {
let bounds = node.bounds();
Self {
diff --git a/native/src/widget.rs b/native/src/widget.rs
index 3677713a..d5c353df 100644
--- a/native/src/widget.rs
+++ b/native/src/widget.rs
@@ -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;
@@ -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;
diff --git a/native/src/widget/tooltip.rs b/native/src/widget/tooltip.rs
new file mode 100644
index 00000000..ab07868c
--- /dev/null
+++ b/native/src/widget/tooltip.rs
@@ -0,0 +1,210 @@
+//! Display a widget over another.
+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,
+ Widget,
+};
+
+/// An element to display a widget over another.
+#[allow(missing_debug_implementations)]
+pub struct Tooltip<'a, Message, Renderer: self::Renderer> {
+ content: Element<'a, Message, Renderer>,
+ tooltip: Text<Renderer>,
+ position: Position,
+ style: <Renderer as container::Renderer>::Style,
+ gap: u16,
+ padding: u16,
+}
+
+impl<'a, Message, Renderer> Tooltip<'a, Message, Renderer>
+where
+ Renderer: self::Renderer,
+{
+ /// Creates an empty [`Tooltip`].
+ ///
+ /// [`Tooltip`]: struct.Tooltip.html
+ pub fn new(
+ content: impl Into<Element<'a, Message, Renderer>>,
+ tooltip: impl ToString,
+ position: Position,
+ ) -> Self {
+ Tooltip {
+ content: content.into(),
+ tooltip: Text::new(tooltip.to_string()),
+ position,
+ style: Default::default(),
+ gap: 0,
+ padding: Renderer::DEFAULT_PADDING,
+ }
+ }
+
+ /// Sets the size of the text of the [`Tooltip`].
+ pub fn size(mut self, size: u16) -> Self {
+ self.tooltip = self.tooltip.size(size);
+ self
+ }
+
+ /// Sets the font of the [`Tooltip`].
+ ///
+ /// [`Font`]: Renderer::Font
+ pub fn font(mut self, font: impl Into<Renderer::Font>) -> Self {
+ self.tooltip = self.tooltip.font(font);
+ 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
+ }
+
+ /// Sets the style of the [`Tooltip`].
+ pub fn style(
+ mut self,
+ style: impl Into<<Renderer as container::Renderer>::Style>,
+ ) -> Self {
+ self.style = style.into();
+ self
+ }
+}
+
+/// The position of the tooltip. Defaults to following the cursor.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Position {
+ /// The tooltip will follow the cursor.
+ FollowCursor,
+ /// The tooltip will appear on the top of the widget.
+ Top,
+ /// The tooltip will appear on the bottom of the widget.
+ Bottom,
+ /// The tooltip will appear on the left of the widget.
+ Left,
+ /// The tooltip will appear on the right of the widget.
+ Right,
+}
+
+impl<'a, Message, Renderer> Widget<Message, Renderer>
+ for Tooltip<'a, Message, Renderer>
+where
+ Renderer: self::Renderer,
+{
+ fn width(&self) -> Length {
+ self.content.width()
+ }
+
+ fn height(&self) -> Length {
+ self.content.height()
+ }
+
+ fn layout(
+ &self,
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ ) -> layout::Node {
+ self.content.layout(renderer, limits)
+ }
+
+ fn on_event(
+ &mut self,
+ event: Event,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ messages: &mut Vec<Message>,
+ renderer: &Renderer,
+ clipboard: Option<&dyn Clipboard>,
+ ) -> event::Status {
+ self.content.widget.on_event(
+ event,
+ layout,
+ cursor_position,
+ messages,
+ renderer,
+ clipboard,
+ )
+ }
+
+ fn draw(
+ &self,
+ renderer: &mut Renderer,
+ defaults: &Renderer::Defaults,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ ) -> Renderer::Output {
+ self::Renderer::draw(
+ renderer,
+ defaults,
+ cursor_position,
+ layout,
+ viewport,
+ &self.content,
+ &self.tooltip,
+ self.position,
+ &self.style,
+ self.gap,
+ self.padding,
+ )
+ }
+
+ fn hash_layout(&self, state: &mut Hasher) {
+ struct Marker;
+ std::any::TypeId::of::<Marker>().hash(state);
+
+ self.content.hash_layout(state);
+ }
+}
+
+/// 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,
+ Message: 'a,
+{
+ fn from(
+ column: Tooltip<'a, Message, Renderer>,
+ ) -> Element<'a, Message, Renderer> {
+ Element::new(column)
+ }
+}
diff --git a/src/widget.rs b/src/widget.rs
index edd35d2d..eac50d57 100644
--- a/src/widget.rs
+++ b/src/widget.rs
@@ -17,7 +17,8 @@
mod platform {
pub use crate::renderer::widget::{
button, checkbox, container, pane_grid, pick_list, progress_bar, radio,
- rule, scrollable, slider, text_input, Column, Row, Space, Text,
+ rule, scrollable, slider, text_input, tooltip, Column, Row, Space,
+ Text,
};
#[cfg(any(feature = "canvas", feature = "glow_canvas"))]
@@ -52,7 +53,7 @@ mod platform {
button::Button, checkbox::Checkbox, container::Container, image::Image,
pane_grid::PaneGrid, pick_list::PickList, progress_bar::ProgressBar,
radio::Radio, rule::Rule, scrollable::Scrollable, slider::Slider,
- svg::Svg, text_input::TextInput,
+ svg::Svg, text_input::TextInput, tooltip::Tooltip,
};
#[cfg(any(feature = "canvas", feature = "glow_canvas"))]
diff --git a/wgpu/src/widget.rs b/wgpu/src/widget.rs
index 177ae1b6..304bb726 100644
--- a/wgpu/src/widget.rs
+++ b/wgpu/src/widget.rs
@@ -20,6 +20,7 @@ pub mod rule;
pub mod scrollable;
pub mod slider;
pub mod text_input;
+pub mod tooltip;
#[doc(no_inline)]
pub use button::Button;
@@ -43,6 +44,8 @@ pub use scrollable::Scrollable;
pub use slider::Slider;
#[doc(no_inline)]
pub use text_input::TextInput;
+#[doc(no_inline)]
+pub use tooltip::Tooltip;
#[cfg(feature = "canvas")]
#[cfg_attr(docsrs, doc(cfg(feature = "canvas")))]
diff --git a/wgpu/src/widget/tooltip.rs b/wgpu/src/widget/tooltip.rs
new file mode 100644
index 00000000..89ab3a15
--- /dev/null
+++ b/wgpu/src/widget/tooltip.rs
@@ -0,0 +1,6 @@
+//! Display a widget over another.
+/// A widget allowing the selection of a single value from a list of options.
+pub type Tooltip<'a, Message> =
+ iced_native::Tooltip<'a, Message, crate::Renderer>;
+
+pub use iced_native::tooltip::Position;