Skip to main content

iced_widget/
pin.rs

1//! A pin widget positions a widget at some fixed coordinates inside its boundaries.
2//!
3//! # Example
4//! ```no_run
5//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; pub use iced_widget::core::Length::Fill; }
6//! # use iced::widget::Widget;
7//! # pub type State = ();
8//! use iced::widget::pin;
9//! use iced::Fill;
10//!
11//! enum Message {
12//!     // ...
13//! }
14//!
15//! fn view(state: &State) -> impl Widget<Message> {
16//!     pin("This text is displayed at coordinates (50, 50)!")
17//!         .x(50)
18//!         .y(50)
19//! }
20//! ```
21use crate::core::layout;
22use crate::core::mouse;
23use crate::core::overlay;
24use crate::core::renderer;
25use crate::core::widget;
26use crate::core::{Event, Layout, Length, Pixels, Point, Rectangle, Shell, Size, Vector, Widget};
27
28/// A widget that positions its contents at some fixed coordinates inside of its boundaries.
29///
30/// By default, a [`Pin`] widget will try to fill its parent.
31///
32/// # Example
33/// ```no_run
34/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; pub use iced_widget::core::Length::Fill; }
35/// # use iced::widget::Widget;
36/// # pub type State = ();
37/// use iced::widget::pin;
38/// use iced::Fill;
39///
40/// enum Message {
41///     // ...
42/// }
43///
44/// fn view(state: &State) -> impl Widget<Message> {
45///     pin("This text is displayed at coordinates (50, 50)!")
46///         .x(50)
47///         .y(50)
48/// }
49/// ```
50pub struct Pin<W> {
51    content: W,
52    width: Length,
53    height: Length,
54    position: Point,
55}
56
57impl<W> Pin<W> {
58    /// Creates a [`Pin`] widget with the given content.
59    pub fn new(content: W) -> Self {
60        Self {
61            content,
62            width: Length::Fill,
63            height: Length::Fill,
64            position: Point::ORIGIN,
65        }
66    }
67
68    /// Sets the width of the [`Pin`].
69    pub fn width(mut self, width: impl Into<Length>) -> Self {
70        self.width = width.into();
71        self
72    }
73
74    /// Sets the height of the [`Pin`].
75    pub fn height(mut self, height: impl Into<Length>) -> Self {
76        self.height = height.into();
77        self
78    }
79
80    /// Sets the position of the [`Pin`]; where the pinned widget will be displayed.
81    pub fn position(mut self, position: impl Into<Point>) -> Self {
82        self.position = position.into();
83        self
84    }
85
86    /// Sets the X coordinate of the [`Pin`].
87    pub fn x(mut self, x: impl Into<Pixels>) -> Self {
88        self.position.x = x.into().0;
89        self
90    }
91
92    /// Sets the Y coordinate of the [`Pin`].
93    pub fn y(mut self, y: impl Into<Pixels>) -> Self {
94        self.position.y = y.into().0;
95        self
96    }
97}
98
99impl<W> widget::Meta for Pin<W> {}
100
101impl<W, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Pin<W>
102where
103    W: Widget<Message, Theme, Renderer>,
104{
105    fn tag(&self) -> widget::tree::Tag {
106        self.content.tag()
107    }
108
109    fn state(&self) -> widget::tree::State {
110        self.content.state()
111    }
112
113    fn diff(&mut self, tree: &mut widget::Tree) {
114        tree.diff_children(std::slice::from_mut(&mut self.content));
115    }
116
117    fn size(&self) -> Size<Length> {
118        Size {
119            width: self.width,
120            height: self.height,
121        }
122    }
123
124    fn layout(&mut self, tree: &mut widget::Tree, renderer: &Renderer, limits: &layout::Limits) {
125        let limits = limits.width(self.width).height(self.height);
126
127        let available = limits.bounds() - Size::new(self.position.x, self.position.y);
128
129        self.content.layout(
130            &mut tree.children[0],
131            renderer,
132            &layout::Limits::new(Size::ZERO, available),
133        );
134
135        tree.children[0].translation = Vector::new(self.position.x, self.position.y);
136        tree.size = limits.resolve(self.width, self.height, tree.children[0].size);
137    }
138
139    fn operate(
140        &mut self,
141        tree: &mut widget::Tree,
142        layout: Layout,
143        viewport: &Rectangle,
144        renderer: &Renderer,
145        operation: &mut dyn widget::Operation,
146    ) {
147        let (layout, tree) = layout.iter_mut(&mut tree.children).next().unwrap();
148
149        self.content
150            .operate(tree, layout, viewport, renderer, operation);
151    }
152
153    fn update(
154        &mut self,
155        tree: &mut widget::Tree,
156        event: &Event,
157        layout: Layout,
158        cursor: mouse::Cursor,
159        renderer: &Renderer,
160        shell: &mut Shell<'_, Message>,
161        viewport: &Rectangle,
162    ) {
163        let (layout, tree) = layout.iter_mut(&mut tree.children).next().unwrap();
164
165        self.content
166            .update(tree, event, layout, cursor, renderer, shell, viewport);
167    }
168
169    fn mouse_interaction(
170        &self,
171        tree: &widget::Tree,
172        layout: Layout,
173        cursor: mouse::Cursor,
174        viewport: &Rectangle,
175        renderer: &Renderer,
176    ) -> mouse::Interaction {
177        let (layout, tree) = layout.iter(&tree.children).next().unwrap();
178
179        self.content
180            .mouse_interaction(tree, layout, cursor, viewport, renderer)
181    }
182
183    fn draw(
184        &self,
185        tree: &widget::Tree,
186        renderer: &mut Renderer,
187        theme: &Theme,
188        style: &renderer::Style,
189        layout: Layout,
190        cursor: mouse::Cursor,
191        viewport: &Rectangle,
192    ) {
193        let bounds = layout.bounds();
194
195        if let Some(clipped_viewport) = bounds.intersection(viewport) {
196            let (layout, tree) = layout.iter(&tree.children).next().unwrap();
197
198            self.content.draw(
199                tree,
200                renderer,
201                theme,
202                style,
203                layout,
204                cursor,
205                &clipped_viewport,
206            );
207        }
208    }
209
210    fn overlay<'b>(
211        &'b mut self,
212        tree: &'b mut widget::Tree,
213        layout: Layout,
214        renderer: &Renderer,
215        viewport: &Rectangle,
216        translation: Vector,
217        window: Size,
218    ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
219        let (layout, tree) = layout.iter_mut(&mut tree.children).next().unwrap();
220
221        self.content
222            .overlay(tree, layout, renderer, viewport, translation, window)
223    }
224}