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