summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón <hector0193@gmail.com>2021-02-24 01:42:08 +0100
committerLibravatar GitHub <noreply@github.com>2021-02-24 01:42:08 +0100
commita5fddf9ee648927b294ef34e8819855d5e117b26 (patch)
tree96f5454cdb07249beefdb0b804de3b10f5ff6cb6 /graphics
parent6759a5c56fc53286d77698ac9a86812b6d7b03ff (diff)
parent2736e4ca35f17a92768f0be682acf6da3b574cb6 (diff)
downloadiced-a5fddf9ee648927b294ef34e8819855d5e117b26.tar.gz
iced-a5fddf9ee648927b294ef34e8819855d5e117b26.tar.bz2
iced-a5fddf9ee648927b294ef34e8819855d5e117b26.zip
Merge pull request #465 from yusdacra/tooltip-widget
Tooltip widget
Diffstat (limited to 'graphics')
-rw-r--r--graphics/src/layer.rs40
-rw-r--r--graphics/src/widget.rs3
-rw-r--r--graphics/src/widget/tooltip.rs145
3 files changed, 176 insertions, 12 deletions
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)
+ }
+ }
+}