Trait kas_core::layout::RowStorage
source · pub trait RowStorage: Clone + Debug + Sealed {
fn set_dim(&mut self, cols: usize);
fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules]);
fn rules(&mut self) -> &mut [SizeRules] { ... }
fn widths(&mut self) -> &mut [i32] { ... }
}
Expand description
Requirements of row solver storage type
Usually this is set by a crate::layout::RowSolver
from
crate::Layout::size_rules
, then used by crate::Layout::set_rect
to
divide the assigned rect between children.
It may be useful to access this directly if not solving size rules normally;
specifically this allows a different size solver to replace size_rules
and
influence set_rect
.
Note: some implementations allocate when Self::set_dim
is first called.
It is expected that this method is called before other methods.
Required Methods§
sourcefn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules])
fn widths_and_rules(&mut self) -> (&mut [i32], &mut [SizeRules])
Access widths and rules simultaneously
Provided Methods§
sourcefn rules(&mut self) -> &mut [SizeRules]
fn rules(&mut self) -> &mut [SizeRules]
Access SizeRules
for each column/row
Examples found in repository?
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
fn for_child<CR: FnOnce(AxisInfo) -> SizeRules>(
&mut self,
storage: &mut Self::Storage,
index: Self::ChildInfo,
child_rules: CR,
) {
if self.axis.has_fixed && self.axis_is_vertical {
self.axis.other_axis = storage.widths()[index];
}
let child_rules = child_rules(self.axis);
if !self.axis_is_vertical {
storage.rules()[index] = child_rules;
if let Some(rules) = self.rules {
if self.axis_is_reversed {
self.rules = Some(child_rules.appended(rules));
} else {
self.rules = Some(rules.appended(child_rules));
}
} else {
self.rules = Some(child_rules);
}
} else {
self.rules = Some(
self.rules
.map(|rules| rules.max(child_rules))
.unwrap_or(child_rules),
);
}
}
fn finish(self, _: &mut Self::Storage) -> SizeRules {
self.rules.unwrap_or(SizeRules::EMPTY)
}
}
/// A [`RulesSetter`] for rows (and, without loss of generality, for columns).
///
/// This is parameterised over:
///
/// - `D:` [`Directional`] — whether this represents a row or a column
/// - `T:` [`RowTemp`] — temporary storage type
/// - `S:` [`RowStorage`] — persistent storage type
pub struct RowSetter<D, T: RowTemp, S: RowStorage> {
rect: Rect,
offsets: T,
direction: D,
_s: PhantomData<S>,
}
impl<D: Directional, T: RowTemp, S: RowStorage> RowSetter<D, T, S> {
/// Construct
///
/// Argument order is consistent with other [`RulesSetter`]s.
///
/// - `rect`: the [`Rect`] within which to position children
/// - `(direction, len)`: direction and number of items
/// - `storage`: access to the solver's storage
pub fn new(rect: Rect, (direction, len): (D, usize), storage: &mut S) -> Self {
let mut offsets = T::default();
offsets.set_len(len);
storage.set_dim(len);
if len > 0 {
let is_horiz = direction.is_horizontal();
let width = if is_horiz { rect.size.0 } else { rect.size.1 };
let (widths, rules) = storage.widths_and_rules();
SizeRules::solve_seq(widths, rules, width);
}
let _s = Default::default();
let mut row = RowSetter {
rect,
offsets,
direction,
_s,
};
row.update_offsets(storage);
row
}
/// Construct without solving
///
/// In this case, it is assumed that the storage was already solved by a
/// previous `RowSetter`. The user should optionally call `solve_range` on
/// any ranges needing updating and finally call `update_offsets` before
/// using this `RowSetter` to calculate child positions.
pub fn new_unsolved(rect: Rect, (direction, len): (D, usize), storage: &mut S) -> Self {
let mut offsets = T::default();
offsets.set_len(len);
storage.set_dim(len);
let _s = Default::default();
RowSetter {
rect,
offsets,
direction,
_s,
}
}
pub fn update_offsets(&mut self, storage: &mut S) {
let offsets = self.offsets.as_mut();
let len = offsets.len();
if len == 0 {
return;
}
let pos = if self.direction.is_horizontal() {
self.rect.pos.0
} else {
self.rect.pos.1
};
if self.direction.is_reversed() {
offsets[len - 1] = pos;
for i in (0..(len - 1)).rev() {
let i1 = i + 1;
let m1 = storage.rules()[i1].margins_i32().1;
let m0 = storage.rules()[i].margins_i32().0;
offsets[i] = offsets[i1] + storage.widths()[i1] + m1.max(m0);
}
} else {
offsets[0] = pos;
for i in 1..len {
let i1 = i - 1;
let m1 = storage.rules()[i1].margins_i32().1;
let m0 = storage.rules()[i].margins_i32().0;
offsets[i] = offsets[i1] + storage.widths()[i1] + m1.max(m0);
}
}
}
pub fn solve_range(&mut self, storage: &mut S, range: Range<usize>, width: i32) {
assert!(range.end <= self.offsets.as_mut().len());
let (widths, rules) = storage.widths_and_rules();
SizeRules::solve_seq(&mut widths[range.clone()], &rules[range], width);
}
}
impl<D: Directional, T: RowTemp, S: RowStorage> RulesSetter for RowSetter<D, T, S> {
type Storage = S;
type ChildInfo = usize;
fn child_rect(&mut self, storage: &mut Self::Storage, index: Self::ChildInfo) -> Rect {
let mut rect = self.rect;
if self.direction.is_horizontal() {
rect.pos.0 = self.offsets.as_mut()[index];
rect.size.0 = storage.widths()[index];
} else {
rect.pos.1 = self.offsets.as_mut()[index];
rect.size.1 = storage.widths()[index];
}
rect
}
fn maximal_rect_of(&mut self, storage: &mut Self::Storage, index: Self::ChildInfo) -> Rect {
let pre_rules = SizeRules::min_sum(&storage.rules()[0..index]);
let m = storage.rules()[index].margins();
let len = storage.widths().len();
let post_rules = SizeRules::min_sum(&storage.rules()[(index + 1)..len]);
let size1 = pre_rules.min_size() + i32::from(pre_rules.margins().1.max(m.0));
let size2 = size1 + post_rules.min_size() + i32::from(post_rules.margins().0.max(m.1));
let mut rect = self.rect;
if self.direction.is_horizontal() {
rect.pos.0 = self.rect.pos.0 + size1;
rect.size.0 = (self.rect.size.0 - size2).max(0);
} else {
rect.pos.1 = self.rect.pos.1 + size1;
rect.size.1 = (self.rect.size.1 - size2).max(0);
}
rect
}
sourcefn widths(&mut self) -> &mut [i32]
fn widths(&mut self) -> &mut [i32]
Access widths for each column/row
Widths are calculated from rules when set_rect
is called. Assigning
to widths before set_rect
is called only has any effect when the available
size exceeds the minimum required (see SizeRules::solve_seq
).
Examples found in repository?
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
fn for_child<CR: FnOnce(AxisInfo) -> SizeRules>(
&mut self,
storage: &mut Self::Storage,
index: Self::ChildInfo,
child_rules: CR,
) {
if self.axis.has_fixed && self.axis_is_vertical {
self.axis.other_axis = storage.widths()[index];
}
let child_rules = child_rules(self.axis);
if !self.axis_is_vertical {
storage.rules()[index] = child_rules;
if let Some(rules) = self.rules {
if self.axis_is_reversed {
self.rules = Some(child_rules.appended(rules));
} else {
self.rules = Some(rules.appended(child_rules));
}
} else {
self.rules = Some(child_rules);
}
} else {
self.rules = Some(
self.rules
.map(|rules| rules.max(child_rules))
.unwrap_or(child_rules),
);
}
}
fn finish(self, _: &mut Self::Storage) -> SizeRules {
self.rules.unwrap_or(SizeRules::EMPTY)
}
}
/// A [`RulesSetter`] for rows (and, without loss of generality, for columns).
///
/// This is parameterised over:
///
/// - `D:` [`Directional`] — whether this represents a row or a column
/// - `T:` [`RowTemp`] — temporary storage type
/// - `S:` [`RowStorage`] — persistent storage type
pub struct RowSetter<D, T: RowTemp, S: RowStorage> {
rect: Rect,
offsets: T,
direction: D,
_s: PhantomData<S>,
}
impl<D: Directional, T: RowTemp, S: RowStorage> RowSetter<D, T, S> {
/// Construct
///
/// Argument order is consistent with other [`RulesSetter`]s.
///
/// - `rect`: the [`Rect`] within which to position children
/// - `(direction, len)`: direction and number of items
/// - `storage`: access to the solver's storage
pub fn new(rect: Rect, (direction, len): (D, usize), storage: &mut S) -> Self {
let mut offsets = T::default();
offsets.set_len(len);
storage.set_dim(len);
if len > 0 {
let is_horiz = direction.is_horizontal();
let width = if is_horiz { rect.size.0 } else { rect.size.1 };
let (widths, rules) = storage.widths_and_rules();
SizeRules::solve_seq(widths, rules, width);
}
let _s = Default::default();
let mut row = RowSetter {
rect,
offsets,
direction,
_s,
};
row.update_offsets(storage);
row
}
/// Construct without solving
///
/// In this case, it is assumed that the storage was already solved by a
/// previous `RowSetter`. The user should optionally call `solve_range` on
/// any ranges needing updating and finally call `update_offsets` before
/// using this `RowSetter` to calculate child positions.
pub fn new_unsolved(rect: Rect, (direction, len): (D, usize), storage: &mut S) -> Self {
let mut offsets = T::default();
offsets.set_len(len);
storage.set_dim(len);
let _s = Default::default();
RowSetter {
rect,
offsets,
direction,
_s,
}
}
pub fn update_offsets(&mut self, storage: &mut S) {
let offsets = self.offsets.as_mut();
let len = offsets.len();
if len == 0 {
return;
}
let pos = if self.direction.is_horizontal() {
self.rect.pos.0
} else {
self.rect.pos.1
};
if self.direction.is_reversed() {
offsets[len - 1] = pos;
for i in (0..(len - 1)).rev() {
let i1 = i + 1;
let m1 = storage.rules()[i1].margins_i32().1;
let m0 = storage.rules()[i].margins_i32().0;
offsets[i] = offsets[i1] + storage.widths()[i1] + m1.max(m0);
}
} else {
offsets[0] = pos;
for i in 1..len {
let i1 = i - 1;
let m1 = storage.rules()[i1].margins_i32().1;
let m0 = storage.rules()[i].margins_i32().0;
offsets[i] = offsets[i1] + storage.widths()[i1] + m1.max(m0);
}
}
}
pub fn solve_range(&mut self, storage: &mut S, range: Range<usize>, width: i32) {
assert!(range.end <= self.offsets.as_mut().len());
let (widths, rules) = storage.widths_and_rules();
SizeRules::solve_seq(&mut widths[range.clone()], &rules[range], width);
}
}
impl<D: Directional, T: RowTemp, S: RowStorage> RulesSetter for RowSetter<D, T, S> {
type Storage = S;
type ChildInfo = usize;
fn child_rect(&mut self, storage: &mut Self::Storage, index: Self::ChildInfo) -> Rect {
let mut rect = self.rect;
if self.direction.is_horizontal() {
rect.pos.0 = self.offsets.as_mut()[index];
rect.size.0 = storage.widths()[index];
} else {
rect.pos.1 = self.offsets.as_mut()[index];
rect.size.1 = storage.widths()[index];
}
rect
}
fn maximal_rect_of(&mut self, storage: &mut Self::Storage, index: Self::ChildInfo) -> Rect {
let pre_rules = SizeRules::min_sum(&storage.rules()[0..index]);
let m = storage.rules()[index].margins();
let len = storage.widths().len();
let post_rules = SizeRules::min_sum(&storage.rules()[(index + 1)..len]);
let size1 = pre_rules.min_size() + i32::from(pre_rules.margins().1.max(m.0));
let size2 = size1 + post_rules.min_size() + i32::from(post_rules.margins().0.max(m.1));
let mut rect = self.rect;
if self.direction.is_horizontal() {
rect.pos.0 = self.rect.pos.0 + size1;
rect.size.0 = (self.rect.size.0 - size2).max(0);
} else {
rect.pos.1 = self.rect.pos.1 + size1;
rect.size.1 = (self.rect.size.1 - size2).max(0);
}
rect
}