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}