diff options
| author | 2024-01-16 12:02:42 +0100 | |
|---|---|---|
| committer | 2024-01-16 12:02:42 +0100 | |
| commit | 534c7dd7b0bc515c31b6de87b4aa6a35b44c46a0 (patch) | |
| tree | 0ddc8f1b681cbade7e47293bd46a362896aa538a /core/src/layout | |
| parent | 17135cbd56316f31167eb62e026839450506573f (diff) | |
| parent | c4ba657de86d7606587dad5124f435141258f570 (diff) | |
| download | iced-534c7dd7b0bc515c31b6de87b4aa6a35b44c46a0.tar.gz iced-534c7dd7b0bc515c31b6de87b4aa6a35b44c46a0.tar.bz2 iced-534c7dd7b0bc515c31b6de87b4aa6a35b44c46a0.zip | |
Merge branch 'master' into update-winit
Diffstat (limited to 'core/src/layout')
| -rw-r--r-- | core/src/layout/flex.rs | 117 | ||||
| -rw-r--r-- | core/src/layout/limits.rs | 88 | ||||
| -rw-r--r-- | core/src/layout/node.rs | 35 | 
3 files changed, 156 insertions, 84 deletions
| diff --git a/core/src/layout/flex.rs b/core/src/layout/flex.rs index c02b63d8..3358ef3d 100644 --- a/core/src/layout/flex.rs +++ b/core/src/layout/flex.rs @@ -20,7 +20,7 @@ use crate::Element;  use crate::layout::{Limits, Node};  use crate::widget; -use crate::{Alignment, Padding, Point, Size}; +use crate::{Alignment, Length, Padding, Point, Size};  /// The main axis of a flex layout.  #[derive(Debug)] @@ -47,7 +47,7 @@ impl Axis {          }      } -    fn pack(&self, main: f32, cross: f32) -> (f32, f32) { +    fn pack<T>(&self, main: T, cross: T) -> (T, T) {          match self {              Axis::Horizontal => (main, cross),              Axis::Vertical => (cross, main), @@ -63,6 +63,8 @@ pub fn resolve<Message, Renderer>(      axis: Axis,      renderer: &Renderer,      limits: &Limits, +    width: Length, +    height: Length,      padding: Padding,      spacing: f32,      align_items: Alignment, @@ -72,26 +74,64 @@ pub fn resolve<Message, Renderer>(  where      Renderer: crate::Renderer,  { -    let limits = limits.pad(padding); +    let limits = limits.width(width).height(height).shrink(padding);      let total_spacing = spacing * items.len().saturating_sub(1) as f32;      let max_cross = axis.cross(limits.max()); -    let mut fill_sum = 0; -    let mut cross = axis.cross(limits.min()).max(axis.cross(limits.fill())); +    let mut fill_main_sum = 0; +    let mut cross = match axis { +        Axis::Horizontal => match height { +            Length::Shrink => 0.0, +            _ => max_cross, +        }, +        Axis::Vertical => match width { +            Length::Shrink => 0.0, +            _ => max_cross, +        }, +    }; +      let mut available = axis.main(limits.max()) - total_spacing;      let mut nodes: Vec<Node> = Vec::with_capacity(items.len());      nodes.resize(items.len(), Node::default());      for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() { -        let fill_factor = match axis { -            Axis::Horizontal => child.as_widget().width(), -            Axis::Vertical => child.as_widget().height(), +        let (fill_main_factor, fill_cross_factor) = { +            let size = child.as_widget().size(); + +            axis.pack(size.width.fill_factor(), size.height.fill_factor()) +        }; + +        if fill_main_factor == 0 { +            if fill_cross_factor == 0 { +                let (max_width, max_height) = axis.pack(available, max_cross); + +                let child_limits = +                    Limits::new(Size::ZERO, Size::new(max_width, max_height)); + +                let layout = +                    child.as_widget().layout(tree, renderer, &child_limits); +                let size = layout.size(); + +                available -= axis.main(size); +                cross = cross.max(axis.cross(size)); + +                nodes[i] = layout; +            } +        } else { +            fill_main_sum += fill_main_factor;          } -        .fill_factor(); +    } -        if fill_factor == 0 { -            let (max_width, max_height) = axis.pack(available, max_cross); +    for (i, (child, tree)) in items.iter().zip(trees.iter_mut()).enumerate() { +        let (fill_main_factor, fill_cross_factor) = { +            let size = child.as_widget().size(); + +            axis.pack(size.width.fill_factor(), size.height.fill_factor()) +        }; + +        if fill_main_factor == 0 && fill_cross_factor != 0 { +            let (max_width, max_height) = axis.pack(available, cross);              let child_limits =                  Limits::new(Size::ZERO, Size::new(max_width, max_height)); @@ -101,34 +141,47 @@ where              let size = layout.size();              available -= axis.main(size); -            cross = cross.max(axis.cross(size)); +            cross = cross.max(axis.cross(layout.size()));              nodes[i] = layout; -        } else { -            fill_sum += fill_factor;          }      } -    let remaining = available.max(0.0); +    let remaining = match axis { +        Axis::Horizontal => match width { +            Length::Shrink => 0.0, +            _ => available.max(0.0), +        }, +        Axis::Vertical => match height { +            Length::Shrink => 0.0, +            _ => available.max(0.0), +        }, +    };      for (i, (child, tree)) in items.iter().zip(trees).enumerate() { -        let fill_factor = match axis { -            Axis::Horizontal => child.as_widget().width(), -            Axis::Vertical => child.as_widget().height(), -        } -        .fill_factor(); +        let (fill_main_factor, fill_cross_factor) = { +            let size = child.as_widget().size(); + +            axis.pack(size.width.fill_factor(), size.height.fill_factor()) +        }; + +        if fill_main_factor != 0 { +            let max_main = +                remaining * fill_main_factor as f32 / fill_main_sum as f32; -        if fill_factor != 0 { -            let max_main = remaining * fill_factor as f32 / fill_sum as f32;              let min_main = if max_main.is_infinite() {                  0.0              } else {                  max_main              }; -            let (min_width, min_height) = -                axis.pack(min_main, axis.cross(limits.min())); +            let max_cross = if fill_cross_factor == 0 { +                max_cross +            } else { +                cross +            }; +            let (min_width, min_height) = axis.pack(min_main, 0.0);              let (max_width, max_height) = axis.pack(max_main, max_cross);              let child_limits = Limits::new( @@ -154,18 +207,18 @@ where          let (x, y) = axis.pack(main, pad.1); -        node.move_to(Point::new(x, y)); +        node.move_to_mut(Point::new(x, y));          match axis {              Axis::Horizontal => { -                node.align( +                node.align_mut(                      Alignment::Start,                      align_items,                      Size::new(0.0, cross),                  );              }              Axis::Vertical => { -                node.align( +                node.align_mut(                      align_items,                      Alignment::Start,                      Size::new(cross, 0.0), @@ -178,8 +231,12 @@ where          main += axis.main(size);      } -    let (width, height) = axis.pack(main - pad.0, cross); -    let size = limits.resolve(Size::new(width, height)); +    let (intrinsic_width, intrinsic_height) = axis.pack(main - pad.0, cross); +    let size = limits.resolve( +        width, +        height, +        Size::new(intrinsic_width, intrinsic_height), +    ); -    Node::with_children(size.pad(padding), nodes) +    Node::with_children(size.expand(padding), nodes)  } diff --git a/core/src/layout/limits.rs b/core/src/layout/limits.rs index 39a3d98b..7fbc7b9d 100644 --- a/core/src/layout/limits.rs +++ b/core/src/layout/limits.rs @@ -1,12 +1,11 @@  #![allow(clippy::manual_clamp)] -use crate::{Length, Padding, Size}; +use crate::{Length, Size};  /// A set of size constraints for layouting.  #[derive(Debug, Clone, Copy, PartialEq)]  pub struct Limits {      min: Size,      max: Size, -    fill: Size,  }  impl Limits { @@ -14,16 +13,11 @@ impl Limits {      pub const NONE: Limits = Limits {          min: Size::ZERO,          max: Size::INFINITY, -        fill: Size::INFINITY,      };      /// Creates new [`Limits`] with the given minimum and maximum [`Size`].      pub const fn new(min: Size, max: Size) -> Limits { -        Limits { -            min, -            max, -            fill: Size::INFINITY, -        } +        Limits { min, max }      }      /// Returns the minimum [`Size`] of the [`Limits`]. @@ -36,26 +30,15 @@ impl Limits {          self.max      } -    /// Returns the fill [`Size`] of the [`Limits`]. -    pub fn fill(&self) -> Size { -        self.fill -    } -      /// Applies a width constraint to the current [`Limits`].      pub fn width(mut self, width: impl Into<Length>) -> Limits {          match width.into() { -            Length::Shrink => { -                self.fill.width = self.min.width; -            } -            Length::Fill | Length::FillPortion(_) => { -                self.fill.width = self.fill.width.min(self.max.width); -            } +            Length::Shrink | Length::Fill | Length::FillPortion(_) => {}              Length::Fixed(amount) => {                  let new_width = amount.min(self.max.width).max(self.min.width);                  self.min.width = new_width;                  self.max.width = new_width; -                self.fill.width = new_width;              }          } @@ -65,19 +48,13 @@ impl Limits {      /// Applies a height constraint to the current [`Limits`].      pub fn height(mut self, height: impl Into<Length>) -> Limits {          match height.into() { -            Length::Shrink => { -                self.fill.height = self.min.height; -            } -            Length::Fill | Length::FillPortion(_) => { -                self.fill.height = self.fill.height.min(self.max.height); -            } +            Length::Shrink | Length::Fill | Length::FillPortion(_) => {}              Length::Fixed(amount) => {                  let new_height =                      amount.min(self.max.height).max(self.min.height);                  self.min.height = new_height;                  self.max.height = new_height; -                self.fill.height = new_height;              }          } @@ -112,13 +89,10 @@ impl Limits {          self      } -    /// Shrinks the current [`Limits`] to account for the given padding. -    pub fn pad(&self, padding: Padding) -> Limits { -        self.shrink(Size::new(padding.horizontal(), padding.vertical())) -    } -      /// Shrinks the current [`Limits`] by the given [`Size`]. -    pub fn shrink(&self, size: Size) -> Limits { +    pub fn shrink(&self, size: impl Into<Size>) -> Limits { +        let size = size.into(); +          let min = Size::new(              (self.min().width - size.width).max(0.0),              (self.min().height - size.height).max(0.0), @@ -129,12 +103,7 @@ impl Limits {              (self.max().height - size.height).max(0.0),          ); -        let fill = Size::new( -            (self.fill.width - size.width).max(0.0), -            (self.fill.height - size.height).max(0.0), -        ); - -        Limits { min, max, fill } +        Limits { min, max }      }      /// Removes the minimum width constraint for the current [`Limits`]. @@ -142,22 +111,39 @@ impl Limits {          Limits {              min: Size::ZERO,              max: self.max, -            fill: self.fill,          }      } -    /// Computes the resulting [`Size`] that fits the [`Limits`] given the -    /// intrinsic size of some content. -    pub fn resolve(&self, intrinsic_size: Size) -> Size { -        Size::new( -            intrinsic_size -                .width -                .min(self.max.width) -                .max(self.fill.width), -            intrinsic_size +    /// Computes the resulting [`Size`] that fits the [`Limits`] given +    /// some width and height requirements and the intrinsic size of +    /// some content. +    pub fn resolve( +        &self, +        width: impl Into<Length>, +        height: impl Into<Length>, +        intrinsic_size: Size, +    ) -> Size { +        let width = match width.into() { +            Length::Fill | Length::FillPortion(_) => self.max.width, +            Length::Fixed(amount) => { +                amount.min(self.max.width).max(self.min.width) +            } +            Length::Shrink => { +                intrinsic_size.width.min(self.max.width).max(self.min.width) +            } +        }; + +        let height = match height.into() { +            Length::Fill | Length::FillPortion(_) => self.max.height, +            Length::Fixed(amount) => { +                amount.min(self.max.height).max(self.min.height) +            } +            Length::Shrink => intrinsic_size                  .height                  .min(self.max.height) -                .max(self.fill.height), -        ) +                .max(self.min.height), +        }; + +        Size::new(width, height)      }  } diff --git a/core/src/layout/node.rs b/core/src/layout/node.rs index 2b44a7d5..5743a9bd 100644 --- a/core/src/layout/node.rs +++ b/core/src/layout/node.rs @@ -1,4 +1,4 @@ -use crate::{Alignment, Point, Rectangle, Size, Vector}; +use crate::{Alignment, Padding, Point, Rectangle, Size, Vector};  /// The bounds of an element and its children.  #[derive(Debug, Clone, Default)] @@ -26,6 +26,14 @@ impl Node {          }      } +    /// Creates a new [`Node`] that wraps a single child with some [`Padding`]. +    pub fn container(child: Self, padding: Padding) -> Self { +        Self::with_children( +            child.bounds.size().expand(padding), +            vec![child.move_to(Point::new(padding.left, padding.top))], +        ) +    } +      /// Returns the [`Size`] of the [`Node`].      pub fn size(&self) -> Size {          Size::new(self.bounds.width, self.bounds.height) @@ -43,6 +51,17 @@ impl Node {      /// Aligns the [`Node`] in the given space.      pub fn align( +        mut self, +        horizontal_alignment: Alignment, +        vertical_alignment: Alignment, +        space: Size, +    ) -> Self { +        self.align_mut(horizontal_alignment, vertical_alignment, space); +        self +    } + +    /// Mutable reference version of [`Self::align`]. +    pub fn align_mut(          &mut self,          horizontal_alignment: Alignment,          vertical_alignment: Alignment, @@ -70,13 +89,23 @@ impl Node {      }      /// Moves the [`Node`] to the given position. -    pub fn move_to(&mut self, position: Point) { +    pub fn move_to(mut self, position: impl Into<Point>) -> Self { +        self.move_to_mut(position); +        self +    } + +    /// Mutable reference version of [`Self::move_to`]. +    pub fn move_to_mut(&mut self, position: impl Into<Point>) { +        let position = position.into(); +          self.bounds.x = position.x;          self.bounds.y = position.y;      }      /// Translates the [`Node`] by the given translation. -    pub fn translate(self, translation: Vector) -> Self { +    pub fn translate(self, translation: impl Into<Vector>) -> Self { +        let translation = translation.into(); +          Self {              bounds: self.bounds + translation,              ..self | 
