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