gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5364Rust 86Markdown 12TOML 91841 Definiciones

⎇ d4374b93f0ec2c0ace42d3feafec22d3af1940d8 src/tree/layout.rs Rust · 204 líneas · 8.1 KB Historia Quién tocó qué crudo

Refactor `LayoutTree` + add examples of custom trees (#564) d4374b93f · Nico Burns ·

1//! Final data structures that represent the high-level UI layout
2use crate::geometry::{Line, Point, Size};
3use crate::prelude::TaffyMaxContent;
4use crate::style::AvailableSpace;
5use crate::util::sys::{f32_max, f32_min};
6
7/// Whether we are performing a full layout, or we merely need to size the node
8#[derive(Copy, Clone, Debug, PartialEq, Eq)]
9pub enum RunMode {
10    /// A full layout for this node and all children should be computed
11    PerformLayout,
12    /// The layout algorithm should be executed such that an accurate container size for the node can be determined.
13    /// Layout steps that aren't necessary for determining the container size of the current node can be skipped.
14    ComputeSize,
15    /// This node should have a null layout set as it has been hidden (i.e. using `Display::None`)
16    PerformHiddenLayout,
17}
18
19/// Whether styles should be taken into account when computing size
20#[derive(Copy, Clone, Debug, PartialEq, Eq)]
21pub enum SizingMode {
22    /// Only content contributions should be taken into account
23    ContentSize,
24    /// Inherent size styles should be taken into account in addition to content contributions
25    InherentSize,
26}
27
28/// A set of margins that are available for collapsing with for block layout's margin collapsing
29#[derive(Copy, Clone, Debug, PartialEq)]
30pub struct CollapsibleMarginSet {
31    /// The largest positive margin
32    positive: f32,
33    /// The smallest negative margin (with largest absolute value)
34    negative: f32,
35}
36
37impl CollapsibleMarginSet {
38    /// A default margin set with no collapsible margins
39    pub const ZERO: Self = Self { positive: 0.0, negative: 0.0 };
40
41    /// Create a set from a single margin
42    pub fn from_margin(margin: f32) -> Self {
43        if margin >= 0.0 {
44            Self { positive: margin, negative: 0.0 }
45        } else {
46            Self { positive: 0.0, negative: margin }
47        }
48    }
49
50    /// Collapse a single margin with this set
51    pub fn collapse_with_margin(mut self, margin: f32) -> Self {
52        if margin >= 0.0 {
53            self.positive = f32_max(self.positive, margin);
54        } else {
55            self.negative = f32_min(self.negative, margin);
56        }
57        self
58    }
59
60    /// Collapse another margin set with this set
61    pub fn collapse_with_set(mut self, other: CollapsibleMarginSet) -> Self {
62        self.positive = f32_max(self.positive, other.positive);
63        self.negative = f32_min(self.negative, other.negative);
64        self
65    }
66
67    /// Resolve the resultant margin from this set once all collapsible margins
68    /// have been collapsed into it
69    pub fn resolve(&self) -> f32 {
70        self.positive + self.negative
71    }
72}
73
74/// A struct containing the inputs constraints/hints for laying out a node, which are passed in by the parent
75#[derive(Debug, Copy, Clone)]
76pub struct LayoutInput {
77    /// Known dimensions represent dimensions (width/height) which should be taken as fixed when performing layout.
78    /// For example, if known_dimensions.width is set to Some(WIDTH) then this means something like:
79    ///
80    ///    "What would the height of this node be, assuming the width is WIDTH"
81    ///
82    /// Layout functions will be called with both known_dimensions set for final layout. Where the meaning is:
83    ///
84    ///   "The exact size of this node is WIDTHxHEIGHT. Please lay out your children"
85    ///
86    pub known_dimensions: Size<Option<f32>>,
87    /// Parent size dimensions are intended to be used for percentage resolution.
88    pub parent_size: Size<Option<f32>>,
89    /// Available space represents an amount of space to layout into, and is used as a soft constraint
90    /// for the purpose of wrapping.
91    pub available_space: Size<AvailableSpace>,
92    /// Whether a Node's style sizes should be taken into account or ignored
93    pub sizing_mode: SizingMode,
94    /// Whether we only need to know the Node's size, or whe
95    pub run_mode: RunMode,
96    /// Specific to CSS Block layout. Used for correctly computing margin collapsing. You probably want to set this to `Line::FALSE`.
97    pub vertical_margins_are_collapsible: Line<bool>,
98}
99
100impl LayoutInput {
101    /// A LayoutInput that can be used to request hidden layout
102    pub const HIDDEN: LayoutInput = LayoutInput {
103        // The important property for hidden layout
104        run_mode: RunMode::PerformHiddenLayout,
105        // The rest will be ignored
106        known_dimensions: Size::NONE,
107        parent_size: Size::NONE,
108        available_space: Size::MAX_CONTENT,
109        sizing_mode: SizingMode::InherentSize,
110        vertical_margins_are_collapsible: Line::FALSE,
111    };
112}
113
114/// A struct containing the result of laying a single node, which is returned up to the parent node
115///
116/// A baseline is the line on which text sits. Your node likely has a baseline if it is a text node, or contains
117/// children that may be text nodes. See <https://www.w3.org/TR/css-writing-modes-3/#intro-baselines> for details.
118/// If your node does not have a baseline (or you are unsure how to compute it), then simply return `Point::NONE`
119/// for the first_baselines field
120#[derive(Debug, Copy, Clone)]
121pub struct LayoutOutput {
122    /// The size of the node
123    pub size: Size<f32>,
124    /// The first baseline of the node in each dimension, if any
125    pub first_baselines: Point<Option<f32>>,
126    /// Top margin that can be collapsed with. This is used for CSS block layout and can be set to
127    /// `CollapsibleMarginSet::ZERO` for other layout modes that don't support margin collapsing
128    pub top_margin: CollapsibleMarginSet,
129    /// Bottom margin that can be collapsed with. This is used for CSS block layout and can be set to
130    /// `CollapsibleMarginSet::ZERO` for other layout modes that don't support margin collapsing
131    pub bottom_margin: CollapsibleMarginSet,
132    /// Whether margins can be collapsed through this node. This is used for CSS block layout and can
133    /// be set to `false` for other layout modes that don't support margin collapsing
134    pub margins_can_collapse_through: bool,
135}
136
137impl LayoutOutput {
138    /// An all-zero `LayoutOutput` for hidden nodes
139    pub const HIDDEN: Self = Self {
140        size: Size::ZERO,
141        first_baselines: Point::NONE,
142        top_margin: CollapsibleMarginSet::ZERO,
143        bottom_margin: CollapsibleMarginSet::ZERO,
144        margins_can_collapse_through: false,
145    };
146
147    /// Constructor to create a `LayoutOutput` from just the size and baselines
148    pub fn from_size_and_baselines(size: Size<f32>, first_baselines: Point<Option<f32>>) -> Self {
149        Self {
150            size,
151            first_baselines,
152            top_margin: CollapsibleMarginSet::ZERO,
153            bottom_margin: CollapsibleMarginSet::ZERO,
154            margins_can_collapse_through: false,
155        }
156    }
157}
158
159impl From<Size<f32>> for LayoutOutput {
160    fn from(size: Size<f32>) -> Self {
161        Self {
162            size,
163            first_baselines: Point::NONE,
164            top_margin: CollapsibleMarginSet::ZERO,
165            bottom_margin: CollapsibleMarginSet::ZERO,
166            margins_can_collapse_through: false,
167        }
168    }
169}
170
171/// The final result of a layout algorithm for a single node.
172#[derive(Debug, Copy, Clone)]
173pub struct Layout {
174    /// The relative ordering of the node
175    ///
176    /// Nodes with a higher order should be rendered on top of those with a lower order.
177    /// This is effectively a topological sort of each tree.
178    pub order: u32,
179    /// The width and height of the node
180    pub size: Size<f32>,
181    /// The top-left corner of the node
182    pub location: Point<f32>,
183}
184
185impl Layout {
186    /// Creates a new zero-[`Layout`].
187    ///
188    /// The Zero-layout has size and location set to ZERO.
189    /// The `order` value of this layout is set to the minimum value of 0.
190    /// This means it should be rendered below all other [`Layout`]s.
191    #[must_use]
192    pub const fn new() -> Self {
193        Self { order: 0, size: Size::zero(), location: Point::ZERO }
194    }
195
196    /// Creates a new zero-[`Layout`] with the supplied `order` value.
197    ///
198    /// Nodes with a higher order should be rendered on top of those with a lower order.
199    /// The Zero-layout has size and location set to ZERO.
200    #[must_use]
201    pub const fn with_order(order: u32) -> Self {
202        Self { order, size: Size::zero(), location: Point::ZERO }
203    }
204}