kas_core/layout/
storage.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 solver — storage
7
8use super::{AxisInfo, SizeRules};
9use crate::dir::Directional;
10use crate::geom::{Offset, Rect, Size};
11use crate::theme::{FrameStyle, SizeCx};
12use kas_macros::impl_scope;
13use std::fmt::Debug;
14
15/// Layout storage for pack
16#[derive(Clone, Default, Debug)]
17pub struct PackStorage {
18    /// Ideal size
19    pub size: Size,
20}
21
22/// Layout storage for frame
23#[derive(Clone, Default, Debug)]
24pub struct FrameStorage {
25    /// Size used by frame (sum of widths of borders)
26    pub size: Size,
27    /// Offset of frame contents from parent position
28    pub offset: Offset,
29    /// [`Rect`] assigned to whole frame
30    ///
31    /// NOTE: for a top-level layout component this is redundant with the
32    /// widget's rect. For frames deeper within a widget's layout we *could*
33    /// instead recalculate this (in every draw call etc.).
34    pub rect: Rect,
35}
36impl FrameStorage {
37    /// Calculate child's "other axis" size
38    pub fn child_axis(&self, mut axis: AxisInfo) -> AxisInfo {
39        axis.sub_other(self.size.extract(axis.flipped()));
40        axis
41    }
42
43    /// Generate [`SizeRules`]
44    pub fn size_rules(
45        &mut self,
46        sizer: SizeCx,
47        axis: AxisInfo,
48        child_rules: SizeRules,
49        style: FrameStyle,
50    ) -> SizeRules {
51        let frame_rules = sizer.frame(style, axis);
52        let (rules, offset, size) = frame_rules.surround(child_rules);
53        self.offset.set_component(axis, offset);
54        self.size.set_component(axis, size);
55        rules
56    }
57}
58
59/// Requirements of row solver storage type
60///
61/// Usually this is set by a [`crate::layout::RowSolver`] from
62/// [`crate::Layout::size_rules`], then used by [`crate::Layout::set_rect`] to
63/// divide the assigned rect between children.
64///
65/// It may be useful to access this directly if not solving size rules normally;
66/// specifically this allows a different size solver to replace `size_rules` and
67/// influence `set_rect`.
68///
69/// Note: some implementations allocate when [`Self::set_dim`] is first called.
70/// It is expected that this method is called before other methods.
71pub trait RowStorage: Clone + Debug + sealed::Sealed {
72    /// Set dimension: number of columns or rows
73    fn set_dim(&mut self, cols: usize);
74
75    /// Access [`SizeRules`] for each column/row
76    fn rules(&mut self) -> &mut [SizeRules] {
77        self.widths_and_rules().1
78    }
79
80    /// Access widths for each column/row
81    ///
82    /// Widths are calculated from rules when `set_rect` is called. Assigning
83    /// to widths before `set_rect` is called only has any effect when the available
84    /// size exceeds the minimum required (see [`SizeRules::solve_seq`]).
85    fn widths(&mut self) -> &mut [i32] {
86        self.widths_and_rules().0
87    }
88
89    /// Access widths and rules simultaneously
90    fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]);
91}
92
93/// Fixed-length row storage
94///
95/// Uses const-generics argument `C` (the number of columns).
96#[derive(Clone, Debug)]
97pub struct FixedRowStorage<const C: usize> {
98    rules: [SizeRules; C],
99    widths: [i32; C],
100}
101
102impl<const C: usize> Default for FixedRowStorage<C> {
103    fn default() -> Self {
104        FixedRowStorage {
105            rules: [SizeRules::default(); C],
106            widths: [0; C],
107        }
108    }
109}
110
111impl<const C: usize> RowStorage for FixedRowStorage<C> {
112    fn set_dim(&mut self, cols: usize) {
113        assert_eq!(self.rules.as_ref().len(), cols);
114        assert_eq!(self.widths.as_ref().len(), cols);
115    }
116
117    fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]) {
118        (self.widths.as_mut(), self.rules.as_mut())
119    }
120}
121
122/// Variable-length row storage
123#[derive(Clone, Debug, Default)]
124pub struct DynRowStorage {
125    rules: Vec<SizeRules>,
126    widths: Vec<i32>,
127}
128
129impl RowStorage for DynRowStorage {
130    fn set_dim(&mut self, cols: usize) {
131        self.rules.resize(cols, SizeRules::EMPTY);
132        self.widths.resize(cols, 0);
133    }
134
135    fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]) {
136        (&mut self.widths, &mut self.rules)
137    }
138}
139
140/// Temporary storage type.
141///
142/// For dynamic-length rows and fixed-length rows with more than 16 items use
143/// `Vec<i32>`. For fixed-length rows up to 16 items, use `[i32; rows]`.
144pub trait RowTemp: AsMut<[i32]> + Default + Debug + sealed::Sealed {
145    fn set_len(&mut self, len: usize);
146}
147
148impl RowTemp for Vec<i32> {
149    fn set_len(&mut self, len: usize) {
150        self.resize(len, 0);
151    }
152}
153
154impl<const L: usize> RowTemp for [i32; L]
155where
156    [i32; L]: Default,
157{
158    fn set_len(&mut self, len: usize) {
159        assert_eq!(self.len(), len);
160    }
161}
162
163/// Requirements of grid solver storage type
164///
165/// Usually this is set by a [`crate::layout::GridSolver`] from
166/// [`crate::Layout::size_rules`], then used by [`crate::Layout::set_rect`] to
167/// divide the assigned rect between children.
168///
169/// It may be useful to access this directly if not solving size rules normally;
170/// specifically this allows a different size solver to replace `size_rules` and
171/// influence `set_rect`.
172///
173/// Note: some implementations allocate when [`Self::set_dims`] is first called.
174/// It is expected that this method is called before other methods.
175pub trait GridStorage: sealed::Sealed + Clone + std::fmt::Debug {
176    /// Set dimension: number of columns and rows
177    fn set_dims(&mut self, cols: usize, rows: usize);
178
179    /// Access [`SizeRules`] for each column
180    fn width_rules(&mut self) -> &mut [SizeRules] {
181        self.widths_and_rules().1
182    }
183
184    /// Access [`SizeRules`] for each row
185    fn height_rules(&mut self) -> &mut [SizeRules] {
186        self.heights_and_rules().1
187    }
188
189    /// Access widths for each column
190    ///
191    /// Widths are calculated from rules when `set_rect` is called. Assigning
192    /// to widths before `set_rect` is called only has any effect when the available
193    /// size exceeds the minimum required (see [`SizeRules::solve_seq`]).
194    fn widths(&mut self) -> &mut [i32] {
195        self.widths_and_rules().0
196    }
197
198    /// Access heights for each row
199    ///
200    /// Heights are calculated from rules when `set_rect` is called. Assigning
201    /// to heights before `set_rect` is called only has any effect when the available
202    /// size exceeds the minimum required (see [`SizeRules::solve_seq`]).
203    fn heights(&mut self) -> &mut [i32] {
204        self.heights_and_rules().0
205    }
206
207    /// Access column widths and rules simultaneously
208    fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]);
209
210    /// Access row heights and rules simultaneously
211    fn heights_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]);
212}
213
214impl_scope! {
215    /// Fixed-length grid storage
216    ///
217    /// Uses const-generics arguments `R, C` (the number of rows and columns).
218    #[impl_default]
219    #[derive(Clone, Debug)]
220    pub struct FixedGridStorage<const C: usize, const R: usize> {
221        width_rules: [SizeRules; C] = [SizeRules::default(); C],
222        height_rules: [SizeRules; R] = [SizeRules::default(); R],
223        widths: [i32; C] = [0; C],
224        heights: [i32; R] = [0; R],
225    }
226
227    impl GridStorage for Self {
228        fn set_dims(&mut self, cols: usize, rows: usize) {
229            assert_eq!(self.width_rules.as_ref().len(), cols);
230            assert_eq!(self.height_rules.as_ref().len(), rows);
231            assert_eq!(self.widths.len(), cols);
232            assert_eq!(self.heights.len(), rows);
233        }
234
235        fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]) {
236            (
237                self.widths.as_mut(),
238                self.width_rules.as_mut(),
239            )
240        }
241        fn heights_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]) {
242            (
243                self.heights.as_mut(),
244                self.height_rules.as_mut(),
245            )
246        }
247    }
248}
249
250/// Variable-length grid storage
251#[derive(Clone, Debug, Default)]
252pub struct DynGridStorage {
253    width_rules: Vec<SizeRules>,
254    height_rules: Vec<SizeRules>,
255    widths: Vec<i32>,
256    heights: Vec<i32>,
257}
258
259impl GridStorage for DynGridStorage {
260    fn set_dims(&mut self, cols: usize, rows: usize) {
261        self.width_rules.resize(cols, SizeRules::EMPTY);
262        self.height_rules.resize(rows, SizeRules::EMPTY);
263        self.widths.resize(cols, 0);
264        self.heights.resize(rows, 0);
265    }
266
267    fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]) {
268        (self.widths.as_mut(), self.width_rules.as_mut())
269    }
270    fn heights_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]) {
271        (self.heights.as_mut(), self.height_rules.as_mut())
272    }
273}
274
275mod sealed {
276    pub trait Sealed {}
277    impl<const C: usize> Sealed for super::FixedRowStorage<C> {}
278    impl Sealed for super::DynRowStorage {}
279    impl Sealed for Vec<i32> {}
280    impl<const L: usize> Sealed for [i32; L] {}
281    impl<const C: usize, const R: usize> Sealed for super::FixedGridStorage<C, R> {}
282    impl Sealed for super::DynGridStorage {}
283}