Skip to main content

kas_core/layout/
mod.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Layout utilities
7//!
8//! For documentation of layout resolution, see the [`Layout`] trait.
9//!
10//! Size units are physical (real) pixels. This applies to most of KAS.
11//!
12//! ## Data types
13//!
14//! [`SizeRules`] is the "heart" of widget layout, used to specify a widget's
15//! size requirements. It provides various methods to compute derived rules
16//! and [`SizeRules::solve_widths`], the "muscle" of the layout engine.
17//!
18//! [`AxisInfo`], [`Margins`] and [`Stretch`] are auxilliary data types.
19//!
20//! ## Solvers
21//!
22//! The [`RulesSolver`] and [`RulesSetter`] traits define interfaces for
23//! layout engines:
24//!
25//! -   [`RowSolver`] and [`RowSetter`] set out a row or column of children.
26//!     These are parametrised over `S: RowStorage` allowing both efficient
27//!     operation on a small fixed number of children with [`FixedRowStorage`]
28//!     and operation on a over a `Vec` with [`DynRowStorage`].
29//! -   [`GridSolver`] and [`GridSetter`] set out children assigned to grid
30//!     cells with optional cell-spans. This is the most powerful and flexible
31//!     layout engine.
32//!
33//! [`RowPositionSolver`] may be used with widgets set out by [`RowSetter`]
34//! to quickly locate children from a `coord` or `rect`.
35//!
36//! [`Layout`]: crate::Layout
37
38mod align;
39mod flow_solver;
40mod grid_solver;
41mod row_solver;
42mod size_rules;
43mod size_types;
44mod sizer;
45mod storage;
46
47#[allow(unused)] use crate::Layout;
48use crate::dir::{Direction, Directional};
49
50pub use align::{Align, AlignHints, AlignPair};
51pub use flow_solver::{FlowSetter, FlowSolver, FlowStorage};
52pub use grid_solver::{DefaultWithLen, GridCellInfo, GridDimensions, GridSetter, GridSolver};
53pub use row_solver::{RowPositionSolver, RowSetter, RowSolver};
54pub use size_rules::SizeRules;
55pub use size_types::*;
56pub use sizer::{RulesSetter, RulesSolver, SolveCache, solve_size_rules};
57pub use storage::*;
58
59/// Information on which axis is being resized
60///
61/// Also conveys the size of the other axis, if fixed.
62#[derive(Copy, Clone, Debug)]
63pub struct AxisInfo {
64    vertical: bool,
65    has_fixed: bool,
66    other_axis: i32,
67}
68
69impl AxisInfo {
70    /// Construct with direction and an optional value for the other axis
71    ///
72    /// This method is *usually* not required by user code.
73    #[inline]
74    pub fn new(vertical: bool, fixed: Option<i32>) -> Self {
75        AxisInfo {
76            vertical,
77            has_fixed: fixed.is_some(),
78            other_axis: fixed.unwrap_or(0),
79        }
80    }
81
82    /// True if the current axis is vertical
83    #[inline]
84    pub fn is_vertical(self) -> bool {
85        self.vertical
86    }
87
88    /// True if the current axis is horizontal
89    #[inline]
90    pub fn is_horizontal(self) -> bool {
91        !self.vertical
92    }
93
94    /// Size of other axis, if fixed
95    ///
96    /// When [sizing](Layout#sizing) the vertical axis, this value represents
97    /// the expected width thus allowing text/content flow to affect vertical
98    /// size requirements.
99    ///
100    /// NOTE: this value may be inaccurate due to lack of testing.
101    #[inline]
102    pub fn other(&self) -> Option<i32> {
103        if self.has_fixed { Some(self.other_axis) } else { None }
104    }
105
106    /// Adjust other axis value
107    pub fn map_other(&mut self, f: impl Fn(i32) -> i32) {
108        self.other_axis = f(self.other_axis);
109    }
110}
111
112impl Directional for AxisInfo {
113    type Flipped = Self;
114    type Reversed = Self;
115
116    fn flipped(mut self) -> Self::Flipped {
117        self.vertical = !self.vertical;
118        self.has_fixed = false;
119        self
120    }
121
122    #[inline]
123    fn reversed(self) -> Self::Reversed {
124        self
125    }
126
127    #[inline]
128    fn as_direction(self) -> Direction {
129        match self.vertical {
130            false => Direction::Right,
131            true => Direction::Down,
132        }
133    }
134}
135
136#[cfg(test)]
137#[test]
138fn size() {
139    assert_eq!(std::mem::size_of::<AxisInfo>(), 8);
140}