diff options
| author | 2024-11-22 04:06:52 +0100 | |
|---|---|---|
| committer | 2024-11-22 04:06:52 +0100 | |
| commit | 5be1d545d0baa09b82fe380d9246f66474cce302 (patch) | |
| tree | 3493b8fecf17740ad67cc9d5fe6f9f9073206098 /widget | |
| parent | 6ccc828607b22a0583c12bad638ee2bc7e7310b8 (diff) | |
| download | iced-5be1d545d0baa09b82fe380d9246f66474cce302.tar.gz iced-5be1d545d0baa09b82fe380d9246f66474cce302.tar.bz2 iced-5be1d545d0baa09b82fe380d9246f66474cce302.zip | |
Implement `pin` widget
Diffstat (limited to '')
| -rw-r--r-- | widget/src/helpers.rs | 36 | ||||
| -rw-r--r-- | widget/src/lib.rs | 3 | ||||
| -rw-r--r-- | widget/src/pin.rs | 272 | 
3 files changed, 310 insertions, 1 deletions
| diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 33dff647..a669b290 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -24,7 +24,7 @@ use crate::text_input::{self, TextInput};  use crate::toggler::{self, Toggler};  use crate::tooltip::{self, Tooltip};  use crate::vertical_slider::{self, VerticalSlider}; -use crate::{Column, MouseArea, Row, Space, Stack, Themer}; +use crate::{Column, MouseArea, Pin, Row, Space, Stack, Themer};  use std::borrow::Borrow;  use std::ops::RangeInclusive; @@ -249,6 +249,40 @@ where      container(content).center(Length::Fill)  } +/// Creates a new [`Pin`] widget with the given content. +/// +/// A [`Pin`] widget positions its contents at some fixed coordinates inside of its boundaries. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::Length::Fill; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::pin; +/// use iced::Fill; +/// +/// enum Message { +///     // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +///     pin("This text is displayed at coordinates (50, 50)!") +///         .width(Fill) +///         .height(Fill) +///         .x(50) +///         .y(50) +///         .into() +/// } +/// ``` +pub fn pin<'a, Message, Theme, Renderer>( +    content: impl Into<Element<'a, Message, Theme, Renderer>>, +) -> Pin<'a, Message, Theme, Renderer> +where +    Renderer: core::Renderer, +{ +    Pin::new(content) +} +  /// Creates a new [`Column`] with the given children.  ///  /// Columns distribute their children vertically. diff --git a/widget/src/lib.rs b/widget/src/lib.rs index 776a04a0..38c9929a 100644 --- a/widget/src/lib.rs +++ b/widget/src/lib.rs @@ -11,6 +11,7 @@ pub use iced_runtime::core;  mod action;  mod column;  mod mouse_area; +mod pin;  mod row;  mod space;  mod stack; @@ -63,6 +64,8 @@ pub use pane_grid::PaneGrid;  #[doc(no_inline)]  pub use pick_list::PickList;  #[doc(no_inline)] +pub use pin::Pin; +#[doc(no_inline)]  pub use progress_bar::ProgressBar;  #[doc(no_inline)]  pub use radio::Radio; diff --git a/widget/src/pin.rs b/widget/src/pin.rs new file mode 100644 index 00000000..7d561894 --- /dev/null +++ b/widget/src/pin.rs @@ -0,0 +1,272 @@ +//! A pin widget positions a widget at some fixed coordinates inside its boundaries. +//! +//! # Example +//! ```no_run +//! # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::Length::Fill; } +//! # pub type State = (); +//! # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +//! use iced::widget::pin; +//! use iced::Fill; +//! +//! enum Message { +//!     // ... +//! } +//! +//! fn view(state: &State) -> Element<'_, Message> { +//!     pin("This text is displayed at coordinates (50, 50)!") +//!         .width(Fill) +//!         .height(Fill) +//!         .x(50) +//!         .y(50) +//!         .into() +//! } +//! ``` +use crate::core::layout; +use crate::core::mouse; +use crate::core::overlay; +use crate::core::renderer; +use crate::core::widget; +use crate::core::{ +    self, Clipboard, Element, Event, Layout, Length, Pixels, Point, Rectangle, +    Shell, Size, Vector, Widget, +}; + +/// A widget that positions its contents at some fixed coordinates inside of its boundaries. +/// +/// # Example +/// ```no_run +/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::Length::Fill; } +/// # pub type State = (); +/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; +/// use iced::widget::pin; +/// use iced::Fill; +/// +/// enum Message { +///     // ... +/// } +/// +/// fn view(state: &State) -> Element<'_, Message> { +///     pin("This text is displayed at coordinates (50, 50)!") +///         .width(Fill) +///         .height(Fill) +///         .x(50) +///         .y(50) +///         .into() +/// } +/// ``` +#[allow(missing_debug_implementations)] +pub struct Pin<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer> +where +    Renderer: core::Renderer, +{ +    content: Element<'a, Message, Theme, Renderer>, +    width: Length, +    height: Length, +    position: Point, +} + +impl<'a, Message, Theme, Renderer> Pin<'a, Message, Theme, Renderer> +where +    Renderer: core::Renderer, +{ +    /// Creates a [`Pin`] widget with the given content. +    pub fn new( +        content: impl Into<Element<'a, Message, Theme, Renderer>>, +    ) -> Self { +        Self { +            content: content.into(), +            width: Length::Shrink, +            height: Length::Shrink, +            position: Point::ORIGIN, +        } +    } + +    /// Sets the width of the [`Pin`]. +    pub fn width(mut self, width: impl Into<Length>) -> Self { +        self.width = width.into(); +        self +    } + +    /// Sets the height of the [`Pin`]. +    pub fn height(mut self, height: impl Into<Length>) -> Self { +        self.height = height.into(); +        self +    } + +    /// Sets the position of the [`Pin`]; where the pinned widget will be displayed. +    pub fn position(mut self, position: impl Into<Point>) -> Self { +        self.position = position.into(); +        self +    } + +    /// Sets the X coordinate of the [`Pin`]. +    pub fn x(mut self, x: impl Into<Pixels>) -> Self { +        self.position.x = x.into().0; +        self +    } + +    /// Sets the Y coordinate of the [`Pin`]. +    pub fn y(mut self, y: impl Into<Pixels>) -> Self { +        self.position.y = y.into().0; +        self +    } +} + +impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer> +    for Pin<'a, Message, Theme, Renderer> +where +    Renderer: core::Renderer, +{ +    fn tag(&self) -> widget::tree::Tag { +        self.content.as_widget().tag() +    } + +    fn state(&self) -> widget::tree::State { +        self.content.as_widget().state() +    } + +    fn children(&self) -> Vec<widget::Tree> { +        self.content.as_widget().children() +    } + +    fn diff(&self, tree: &mut widget::Tree) { +        self.content.as_widget().diff(tree); +    } + +    fn size(&self) -> Size<Length> { +        Size { +            width: self.width, +            height: self.height, +        } +    } + +    fn layout( +        &self, +        tree: &mut widget::Tree, +        renderer: &Renderer, +        limits: &layout::Limits, +    ) -> layout::Node { +        let limits = limits.width(self.width).height(self.height); + +        let available = +            limits.max() - Size::new(self.position.x, self.position.y); + +        let node = self +            .content +            .as_widget() +            .layout(tree, renderer, &layout::Limits::new(Size::ZERO, available)) +            .move_to(self.position); + +        let size = limits.resolve(self.width, self.height, node.size()); +        layout::Node::with_children(size, vec![node]) +    } + +    fn operate( +        &self, +        tree: &mut widget::Tree, +        layout: Layout<'_>, +        renderer: &Renderer, +        operation: &mut dyn widget::Operation, +    ) { +        self.content.as_widget().operate( +            tree, +            layout.children().next().unwrap(), +            renderer, +            operation, +        ); +    } + +    fn update( +        &mut self, +        tree: &mut widget::Tree, +        event: Event, +        layout: Layout<'_>, +        cursor: mouse::Cursor, +        renderer: &Renderer, +        clipboard: &mut dyn Clipboard, +        shell: &mut Shell<'_, Message>, +        viewport: &Rectangle, +    ) { +        self.content.as_widget_mut().update( +            tree, +            event, +            layout.children().next().unwrap(), +            cursor, +            renderer, +            clipboard, +            shell, +            viewport, +        ); +    } + +    fn mouse_interaction( +        &self, +        tree: &widget::Tree, +        layout: Layout<'_>, +        cursor: mouse::Cursor, +        viewport: &Rectangle, +        renderer: &Renderer, +    ) -> mouse::Interaction { +        self.content.as_widget().mouse_interaction( +            tree, +            layout.children().next().unwrap(), +            cursor, +            viewport, +            renderer, +        ) +    } + +    fn draw( +        &self, +        tree: &widget::Tree, +        renderer: &mut Renderer, +        theme: &Theme, +        style: &renderer::Style, +        layout: Layout<'_>, +        cursor: mouse::Cursor, +        viewport: &Rectangle, +    ) { +        let bounds = layout.bounds(); + +        if let Some(clipped_viewport) = bounds.intersection(viewport) { +            self.content.as_widget().draw( +                tree, +                renderer, +                theme, +                style, +                layout.children().next().unwrap(), +                cursor, +                &clipped_viewport, +            ); +        } +    } + +    fn overlay<'b>( +        &'b mut self, +        tree: &'b mut widget::Tree, +        layout: Layout<'_>, +        renderer: &Renderer, +        translation: Vector, +    ) -> Option<overlay::Element<'b, Message, Theme, Renderer>> { +        self.content.as_widget_mut().overlay( +            tree, +            layout.children().next().unwrap(), +            renderer, +            translation, +        ) +    } +} + +impl<'a, Message, Theme, Renderer> From<Pin<'a, Message, Theme, Renderer>> +    for Element<'a, Message, Theme, Renderer> +where +    Message: 'a, +    Theme: 'a, +    Renderer: core::Renderer + 'a, +{ +    fn from( +        pin: Pin<'a, Message, Theme, Renderer>, +    ) -> Element<'a, Message, Theme, Renderer> { +        Element::new(pin) +    } +} | 
