diff options
author | 2022-02-12 14:07:04 +0700 | |
---|---|---|
committer | 2022-02-12 14:07:04 +0700 | |
commit | 182fb9446c577a6be988052a5103010e1a79addd (patch) | |
tree | 142dafc8fd6821dd4800828b1063cb3e505a704b /pure | |
parent | 8b27083cdaa2ef7b749e0fd2c1a94b5606ed1c3d (diff) | |
download | iced-182fb9446c577a6be988052a5103010e1a79addd.tar.gz iced-182fb9446c577a6be988052a5103010e1a79addd.tar.bz2 iced-182fb9446c577a6be988052a5103010e1a79addd.zip |
Implement `Container` widget in `iced_pure`
Diffstat (limited to '')
-rw-r--r-- | pure/src/widget.rs | 11 | ||||
-rw-r--r-- | pure/src/widget/container.rs | 258 |
2 files changed, 269 insertions, 0 deletions
diff --git a/pure/src/widget.rs b/pure/src/widget.rs index 1cbd3b78..3bf6a5aa 100644 --- a/pure/src/widget.rs +++ b/pure/src/widget.rs @@ -1,5 +1,6 @@ mod button; mod column; +mod container; mod element; mod row; mod text; @@ -7,6 +8,7 @@ mod tree; pub use button::Button; pub use column::Column; +pub use container::Container; pub use element::Element; pub use row::Row; pub use text::Text; @@ -74,6 +76,15 @@ pub trait Widget<Message, Renderer> { } } +pub fn container<'a, Message, Renderer>( + content: impl Into<Element<'a, Message, Renderer>>, +) -> Container<'a, Message, Renderer> +where + Renderer: iced_native::Renderer, +{ + Container::new(content) +} + pub fn column<'a, Message, Renderer>() -> Column<'a, Message, Renderer> { Column::new() } diff --git a/pure/src/widget/container.rs b/pure/src/widget/container.rs new file mode 100644 index 00000000..94a6b07b --- /dev/null +++ b/pure/src/widget/container.rs @@ -0,0 +1,258 @@ +//! Decorate content and apply alignment. +use crate::{Element, Tree, Widget}; + +use iced_native::alignment; +use iced_native::event::{self, Event}; +use iced_native::layout; +use iced_native::mouse; +use iced_native::renderer; +use iced_native::widget::container; +use iced_native::{ + Clipboard, Hasher, Layout, Length, Padding, Point, Rectangle, Shell, +}; + +use std::any::{self, Any}; +use std::hash::Hash; +use std::u32; + +pub use iced_style::container::{Style, StyleSheet}; + +/// An element decorating some content. +/// +/// It is normally used for alignment purposes. +#[allow(missing_debug_implementations)] +pub struct Container<'a, Message, Renderer> { + padding: Padding, + width: Length, + height: Length, + max_width: u32, + max_height: u32, + horizontal_alignment: alignment::Horizontal, + vertical_alignment: alignment::Vertical, + style_sheet: Box<dyn StyleSheet + 'a>, + content: Element<'a, Message, Renderer>, +} + +impl<'a, Message, Renderer> Container<'a, Message, Renderer> +where + Renderer: iced_native::Renderer, +{ + /// Creates an empty [`Container`]. + pub fn new<T>(content: T) -> Self + where + T: Into<Element<'a, Message, Renderer>>, + { + Container { + padding: Padding::ZERO, + width: Length::Shrink, + height: Length::Shrink, + max_width: u32::MAX, + max_height: u32::MAX, + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + style_sheet: Default::default(), + content: content.into(), + } + } + + /// Sets the [`Padding`] of the [`Container`]. + pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self { + self.padding = padding.into(); + self + } + + /// Sets the width of the [`Container`]. + pub fn width(mut self, width: Length) -> Self { + self.width = width; + self + } + + /// Sets the height of the [`Container`]. + pub fn height(mut self, height: Length) -> Self { + self.height = height; + self + } + + /// Sets the maximum width of the [`Container`]. + pub fn max_width(mut self, max_width: u32) -> Self { + self.max_width = max_width; + self + } + + /// Sets the maximum height of the [`Container`] in pixels. + pub fn max_height(mut self, max_height: u32) -> Self { + self.max_height = max_height; + self + } + + /// Sets the content alignment for the horizontal axis of the [`Container`]. + pub fn align_x(mut self, alignment: alignment::Horizontal) -> Self { + self.horizontal_alignment = alignment; + self + } + + /// Sets the content alignment for the vertical axis of the [`Container`]. + pub fn align_y(mut self, alignment: alignment::Vertical) -> Self { + self.vertical_alignment = alignment; + self + } + + /// Centers the contents in the horizontal axis of the [`Container`]. + pub fn center_x(mut self) -> Self { + self.horizontal_alignment = alignment::Horizontal::Center; + self + } + + /// Centers the contents in the vertical axis of the [`Container`]. + pub fn center_y(mut self) -> Self { + self.vertical_alignment = alignment::Vertical::Center; + self + } + + /// Sets the style of the [`Container`]. + pub fn style( + mut self, + style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + ) -> Self { + self.style_sheet = style_sheet.into(); + self + } +} + +impl<'a, Message, Renderer> Widget<Message, Renderer> + for Container<'a, Message, Renderer> +where + Renderer: iced_native::Renderer, +{ + fn tag(&self) -> any::TypeId { + any::TypeId::of::<()>() + } + + fn state(&self) -> Box<dyn Any> { + Box::new(()) + } + + fn children(&self) -> &[Element<Message, Renderer>] { + std::slice::from_ref(&self.content) + } + + fn width(&self) -> Length { + self.width + } + + fn height(&self) -> Length { + self.height + } + + fn layout( + &self, + renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + container::layout( + renderer, + limits, + self.width, + self.height, + self.padding, + self.horizontal_alignment, + self.vertical_alignment, + |renderer, limits| { + self.content.as_widget().layout(renderer, limits) + }, + ) + } + + fn on_event( + &mut self, + tree: &mut Tree, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + renderer: &Renderer, + clipboard: &mut dyn Clipboard, + shell: &mut Shell<'_, Message>, + ) -> event::Status { + self.content.as_widget_mut().on_event( + &mut tree.children[0], + event, + layout.children().next().unwrap(), + cursor_position, + renderer, + clipboard, + shell, + ) + } + + fn mouse_interaction( + &self, + tree: &Tree, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + renderer: &Renderer, + ) -> mouse::Interaction { + self.content.as_widget().mouse_interaction( + &tree.children[0], + layout.children().next().unwrap(), + cursor_position, + viewport, + renderer, + ) + } + + fn draw( + &self, + tree: &Tree, + renderer: &mut Renderer, + renderer_style: &renderer::Style, + layout: Layout<'_>, + cursor_position: Point, + viewport: &Rectangle, + ) { + let style = self.style_sheet.style(); + + container::draw_background(renderer, &style, layout.bounds()); + + self.content.as_widget().draw( + &tree.children[0], + renderer, + &renderer::Style { + text_color: style + .text_color + .unwrap_or(renderer_style.text_color), + }, + layout.children().next().unwrap(), + cursor_position, + viewport, + ); + } + + fn hash_layout(&self, state: &mut Hasher) { + struct Marker; + std::any::TypeId::of::<Marker>().hash(state); + + self.padding.hash(state); + self.width.hash(state); + self.height.hash(state); + self.max_width.hash(state); + self.max_height.hash(state); + self.horizontal_alignment.hash(state); + self.vertical_alignment.hash(state); + + self.content.as_widget().hash_layout(state); + } +} + +impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>> + for Element<'a, Message, Renderer> +where + Renderer: 'a + iced_native::Renderer, + Message: 'a, +{ + fn from( + column: Container<'a, Message, Renderer>, + ) -> Element<'a, Message, Renderer> { + Element::new(column) + } +} |