summaryrefslogtreecommitdiffstats
path: root/widget/src/container.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-04 05:37:11 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-04 05:37:11 +0100
commit3a0d34c0240f4421737a6a08761f99d6f8140d02 (patch)
treec9a4a6b8e9c1db1b8fcd05bc98e3f131d5ef4bd5 /widget/src/container.rs
parentc54409d1711e1f615c7ea4b02c082954e340632a (diff)
downloadiced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.gz
iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.bz2
iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.zip
Create `iced_widget` subcrate and re-organize the whole codebase
Diffstat (limited to 'widget/src/container.rs')
-rw-r--r--widget/src/container.rs368
1 files changed, 368 insertions, 0 deletions
diff --git a/widget/src/container.rs b/widget/src/container.rs
new file mode 100644
index 00000000..9d932772
--- /dev/null
+++ b/widget/src/container.rs
@@ -0,0 +1,368 @@
+//! Decorate content and apply alignment.
+use crate::core::alignment::{self, Alignment};
+use crate::core::event::{self, Event};
+use crate::core::layout;
+use crate::core::mouse;
+use crate::core::overlay;
+use crate::core::renderer;
+use crate::core::widget::{self, Operation, Tree};
+use crate::core::{
+ Background, Clipboard, Color, Element, Layout, Length, Padding, Pixels,
+ Point, Rectangle, Shell, Widget,
+};
+
+pub use iced_style::container::{Appearance, StyleSheet};
+
+/// An element decorating some content.
+///
+/// It is normally used for alignment purposes.
+#[allow(missing_debug_implementations)]
+pub struct Container<'a, Message, Renderer = crate::Renderer>
+where
+ Renderer: crate::core::Renderer,
+ Renderer::Theme: StyleSheet,
+{
+ id: Option<Id>,
+ padding: Padding,
+ width: Length,
+ height: Length,
+ max_width: f32,
+ max_height: f32,
+ horizontal_alignment: alignment::Horizontal,
+ vertical_alignment: alignment::Vertical,
+ style: <Renderer::Theme as StyleSheet>::Style,
+ content: Element<'a, Message, Renderer>,
+}
+
+impl<'a, Message, Renderer> Container<'a, Message, Renderer>
+where
+ Renderer: crate::core::Renderer,
+ Renderer::Theme: StyleSheet,
+{
+ /// Creates an empty [`Container`].
+ pub fn new<T>(content: T) -> Self
+ where
+ T: Into<Element<'a, Message, Renderer>>,
+ {
+ Container {
+ id: None,
+ padding: Padding::ZERO,
+ width: Length::Shrink,
+ height: Length::Shrink,
+ max_width: f32::INFINITY,
+ max_height: f32::INFINITY,
+ horizontal_alignment: alignment::Horizontal::Left,
+ vertical_alignment: alignment::Vertical::Top,
+ style: Default::default(),
+ content: content.into(),
+ }
+ }
+
+ /// Sets the [`Id`] of the [`Container`].
+ pub fn id(mut self, id: Id) -> Self {
+ self.id = Some(id);
+ self
+ }
+
+ /// 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: impl Into<Length>) -> Self {
+ self.width = width.into();
+ self
+ }
+
+ /// Sets the height of the [`Container`].
+ pub fn height(mut self, height: impl Into<Length>) -> Self {
+ self.height = height.into();
+ self
+ }
+
+ /// Sets the maximum width of the [`Container`].
+ pub fn max_width(mut self, max_width: impl Into<Pixels>) -> Self {
+ self.max_width = max_width.into().0;
+ self
+ }
+
+ /// Sets the maximum height of the [`Container`].
+ pub fn max_height(mut self, max_height: impl Into<Pixels>) -> Self {
+ self.max_height = max_height.into().0;
+ 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: impl Into<<Renderer::Theme as StyleSheet>::Style>,
+ ) -> Self {
+ self.style = style.into();
+ self
+ }
+}
+
+impl<'a, Message, Renderer> Widget<Message, Renderer>
+ for Container<'a, Message, Renderer>
+where
+ Renderer: crate::core::Renderer,
+ Renderer::Theme: StyleSheet,
+{
+ fn children(&self) -> Vec<Tree> {
+ vec![Tree::new(&self.content)]
+ }
+
+ fn diff(&self, tree: &mut Tree) {
+ tree.diff_children(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 {
+ layout(
+ renderer,
+ limits,
+ self.width,
+ self.height,
+ self.max_width,
+ self.max_height,
+ self.padding,
+ self.horizontal_alignment,
+ self.vertical_alignment,
+ |renderer, limits| {
+ self.content.as_widget().layout(renderer, limits)
+ },
+ )
+ }
+
+ fn operate(
+ &self,
+ tree: &mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ operation: &mut dyn Operation<Message>,
+ ) {
+ operation.container(
+ self.id.as_ref().map(|id| &id.0),
+ &mut |operation| {
+ self.content.as_widget().operate(
+ &mut tree.children[0],
+ layout.children().next().unwrap(),
+ renderer,
+ operation,
+ );
+ },
+ );
+ }
+
+ 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,
+ theme: &Renderer::Theme,
+ renderer_style: &renderer::Style,
+ layout: Layout<'_>,
+ cursor_position: Point,
+ viewport: &Rectangle,
+ ) {
+ let style = theme.appearance(&self.style);
+
+ draw_background(renderer, &style, layout.bounds());
+
+ self.content.as_widget().draw(
+ &tree.children[0],
+ renderer,
+ theme,
+ &renderer::Style {
+ text_color: style
+ .text_color
+ .unwrap_or(renderer_style.text_color),
+ },
+ layout.children().next().unwrap(),
+ cursor_position,
+ viewport,
+ );
+ }
+
+ fn overlay<'b>(
+ &'b mut self,
+ tree: &'b mut Tree,
+ layout: Layout<'_>,
+ renderer: &Renderer,
+ ) -> Option<overlay::Element<'b, Message, Renderer>> {
+ self.content.as_widget_mut().overlay(
+ &mut tree.children[0],
+ layout.children().next().unwrap(),
+ renderer,
+ )
+ }
+}
+
+impl<'a, Message, Renderer> From<Container<'a, Message, Renderer>>
+ for Element<'a, Message, Renderer>
+where
+ Message: 'a,
+ Renderer: 'a + crate::core::Renderer,
+ Renderer::Theme: StyleSheet,
+{
+ fn from(
+ column: Container<'a, Message, Renderer>,
+ ) -> Element<'a, Message, Renderer> {
+ Element::new(column)
+ }
+}
+
+/// Computes the layout of a [`Container`].
+pub fn layout<Renderer>(
+ renderer: &Renderer,
+ limits: &layout::Limits,
+ width: Length,
+ height: Length,
+ max_width: f32,
+ max_height: f32,
+ padding: Padding,
+ horizontal_alignment: alignment::Horizontal,
+ vertical_alignment: alignment::Vertical,
+ layout_content: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node,
+) -> layout::Node {
+ let limits = limits
+ .loose()
+ .max_width(max_width)
+ .max_height(max_height)
+ .width(width)
+ .height(height);
+
+ let mut content = layout_content(renderer, &limits.pad(padding).loose());
+ let padding = padding.fit(content.size(), limits.max());
+ let size = limits.pad(padding).resolve(content.size());
+
+ content.move_to(Point::new(padding.left, padding.top));
+ content.align(
+ Alignment::from(horizontal_alignment),
+ Alignment::from(vertical_alignment),
+ size,
+ );
+
+ layout::Node::with_children(size.pad(padding), vec![content])
+}
+
+/// Draws the background of a [`Container`] given its [`Appearance`] and its `bounds`.
+pub fn draw_background<Renderer>(
+ renderer: &mut Renderer,
+ appearance: &Appearance,
+ bounds: Rectangle,
+) where
+ Renderer: crate::core::Renderer,
+{
+ if appearance.background.is_some() || appearance.border_width > 0.0 {
+ renderer.fill_quad(
+ renderer::Quad {
+ bounds,
+ border_radius: appearance.border_radius.into(),
+ border_width: appearance.border_width,
+ border_color: appearance.border_color,
+ },
+ appearance
+ .background
+ .unwrap_or(Background::Color(Color::TRANSPARENT)),
+ );
+ }
+}
+
+/// The identifier of a [`Container`].
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Id(widget::Id);
+
+impl Id {
+ /// Creates a custom [`Id`].
+ pub fn new(id: impl Into<std::borrow::Cow<'static, str>>) -> Self {
+ Self(widget::Id::new(id))
+ }
+
+ /// Creates a unique [`Id`].
+ ///
+ /// This function produces a different [`Id`] every time it is called.
+ pub fn unique() -> Self {
+ Self(widget::Id::unique())
+ }
+}
+
+impl From<Id> for widget::Id {
+ fn from(id: Id) -> Self {
+ id.0
+ }
+}