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