//! Decorate content and apply alignment. use std::hash::Hash; use crate::alignment::{self, Alignment}; use crate::event::{self, Event}; use crate::layout; use crate::mouse; use crate::overlay; use crate::renderer; use crate::{ Background, Clipboard, Color, Element, Hasher, Layout, Length, Padding, Point, Rectangle, Shell, Widget, }; 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, content: Element<'a, Message, Renderer>, } impl<'a, Message, Renderer> Container<'a, Message, Renderer> where Renderer: crate::Renderer, { /// Creates an empty [`Container`]. pub fn new(content: T) -> Self where T: Into>, { 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>(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>, ) -> Self { self.style_sheet = style_sheet.into(); self } } impl<'a, Message, Renderer> Widget for Container<'a, Message, Renderer> where Renderer: crate::Renderer, { fn width(&self) -> Length { self.width } fn height(&self) -> Length { self.height } fn layout( &self, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { let limits = limits .loose() .max_width(self.max_width) .max_height(self.max_height) .width(self.width) .height(self.height) .pad(self.padding); let mut content = self.content.layout(renderer, &limits.loose()); let size = limits.resolve(content.size()); content.move_to(Point::new( self.padding.left.into(), self.padding.top.into(), )); content.align( Alignment::from(self.horizontal_alignment), Alignment::from(self.vertical_alignment), size, ); layout::Node::with_children(size.pad(self.padding), vec![content]) } fn on_event( &mut self, event: Event, layout: Layout<'_>, cursor_position: Point, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, ) -> event::Status { self.content.widget.on_event( event, layout.children().next().unwrap(), cursor_position, renderer, clipboard, shell, ) } fn mouse_interaction( &self, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) -> mouse::Interaction { self.content.widget.mouse_interaction( layout.children().next().unwrap(), cursor_position, viewport, ) } fn draw( &self, renderer: &mut Renderer, renderer_style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, viewport: &Rectangle, ) { let style = self.style_sheet.style(); draw_background(renderer, &style, layout.bounds()); self.content.draw( 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::().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.hash_layout(state); } fn overlay( &mut self, layout: Layout<'_>, ) -> Option> { self.content.overlay(layout.children().next().unwrap()) } } /// Draws the background of a [`Container`] given its [`Style`] and its `bounds`. pub fn draw_background( renderer: &mut Renderer, style: &Style, bounds: Rectangle, ) where Renderer: crate::Renderer, { if style.background.is_some() || style.border_width > 0.0 { renderer.fill_quad( renderer::Quad { bounds, border_radius: style.border_radius, border_width: style.border_width, border_color: style.border_color, }, style .background .unwrap_or(Background::Color(Color::TRANSPARENT)), ); } } impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where Renderer: 'a + crate::Renderer, Message: 'a, { fn from( column: Container<'a, Message, Renderer>, ) -> Element<'a, Message, Renderer> { Element::new(column) } }