Skip to main content

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