use std::marker::PhantomData;
use super::{AxisInfo, SizeRules};
use super::{GridStorage, RowTemp, RulesSetter, RulesSolver};
use crate::cast::{Cast, Conv};
use crate::geom::{Coord, Offset, Rect, Size};
pub trait DefaultWithLen {
fn default_with_len(len: usize) -> Self;
}
impl<T: Copy + Default, const N: usize> DefaultWithLen for [T; N] {
fn default_with_len(len: usize) -> Self {
assert_eq!(len, N);
[Default::default(); N]
}
}
impl<T: Clone + Default> DefaultWithLen for Vec<T> {
fn default_with_len(len: usize) -> Self {
let mut v = Vec::new();
v.resize_with(len, Default::default);
v
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct GridDimensions {
pub cols: u32,
pub col_spans: u32,
pub rows: u32,
pub row_spans: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct GridChildInfo {
pub col: u32,
pub col_end: u32,
pub row: u32,
pub row_end: u32,
}
impl GridChildInfo {
pub fn new(col: u32, row: u32) -> Self {
GridChildInfo {
col,
col_end: col + 1,
row,
row_end: row + 1,
}
}
}
pub struct GridSolver<CSR, RSR, S: GridStorage> {
axis: AxisInfo,
col_spans: CSR,
row_spans: RSR,
next_col_span: usize,
next_row_span: usize,
_s: PhantomData<S>,
}
impl<CSR: DefaultWithLen, RSR: DefaultWithLen, S: GridStorage> GridSolver<CSR, RSR, S> {
pub fn new(axis: AxisInfo, dim: GridDimensions, storage: &mut S) -> Self {
let col_spans = CSR::default_with_len(dim.col_spans.cast());
let row_spans = RSR::default_with_len(dim.row_spans.cast());
storage.set_dims(dim.cols.cast(), dim.rows.cast());
let mut solver = GridSolver {
axis,
col_spans,
row_spans,
next_col_span: 0,
next_row_span: 0,
_s: Default::default(),
};
solver.prepare(storage);
solver
}
fn prepare(&mut self, storage: &mut S) {
if self.axis.has_fixed {
if self.axis.is_vertical() {
let (widths, rules) = storage.widths_and_rules();
SizeRules::solve_seq(widths, rules, self.axis.other_axis);
} else {
let (heights, rules) = storage.heights_and_rules();
SizeRules::solve_seq(heights, rules, self.axis.other_axis);
}
}
if self.axis.is_horizontal() {
for n in 0..storage.width_rules().len() {
storage.width_rules()[n] = SizeRules::EMPTY;
}
} else {
for n in 0..storage.height_rules().len() {
storage.height_rules()[n] = SizeRules::EMPTY;
}
}
}
}
impl<CSR, RSR, S: GridStorage> RulesSolver for GridSolver<CSR, RSR, S>
where
CSR: AsRef<[(SizeRules, u32, u32)]> + AsMut<[(SizeRules, u32, u32)]>,
RSR: AsRef<[(SizeRules, u32, u32)]> + AsMut<[(SizeRules, u32, u32)]>,
{
type Storage = S;
type ChildInfo = GridChildInfo;
fn for_child<CR: FnOnce(AxisInfo) -> SizeRules>(
&mut self,
storage: &mut Self::Storage,
info: Self::ChildInfo,
child_rules: CR,
) {
if self.axis.has_fixed {
if self.axis.is_horizontal() {
self.axis.other_axis = ((info.row + 1)..info.row_end)
.fold(storage.heights()[usize::conv(info.row)], |h, i| {
h + storage.heights()[usize::conv(i)]
});
} else {
self.axis.other_axis = ((info.col + 1)..info.col_end)
.fold(storage.widths()[usize::conv(info.col)], |w, i| {
w + storage.widths()[usize::conv(i)]
});
}
}
let child_rules = child_rules(self.axis);
if self.axis.is_horizontal() {
if info.col_end > info.col + 1 {
let span = &mut self.col_spans.as_mut()[self.next_col_span];
span.0.max_with(child_rules);
span.1 = info.col;
span.2 = info.col_end;
self.next_col_span += 1;
} else {
storage.width_rules()[usize::conv(info.col)].max_with(child_rules);
}
} else if info.row_end > info.row + 1 {
let span = &mut self.row_spans.as_mut()[self.next_row_span];
span.0.max_with(child_rules);
span.1 = info.row;
span.2 = info.row_end;
self.next_row_span += 1;
} else {
storage.height_rules()[usize::conv(info.row)].max_with(child_rules);
};
}
fn finish(mut self, storage: &mut Self::Storage) -> SizeRules {
fn calculate(widths: &mut [SizeRules], spans: &mut [(SizeRules, u32, u32)]) -> SizeRules {
const BASE_WEIGHT: u32 = 100;
const SPAN_WEIGHT: u32 = 10;
let mut scores: Vec<u32> = widths
.iter()
.map(|w| w.stretch() as u32 * BASE_WEIGHT)
.collect();
for span in spans.iter() {
let w = span.0.stretch() as u32 * SPAN_WEIGHT;
for score in &mut scores[(usize::conv(span.1))..(usize::conv(span.2))] {
*score += w;
}
}
for span in spans.iter() {
let range = (usize::conv(span.1))..(usize::conv(span.2));
span.0
.distribute_stretch_over_by(&mut widths[range.clone()], &scores[range]);
}
spans.sort_by_key(|span| span.2.saturating_sub(span.1));
for span in spans {
let rules = span.0;
let begin = usize::conv(span.1);
let end = usize::conv(span.2);
rules.distribute_span_over(&mut widths[begin..end]);
}
SizeRules::sum(widths)
}
if self.axis.is_horizontal() {
calculate(storage.width_rules(), self.col_spans.as_mut())
} else {
calculate(storage.height_rules(), self.row_spans.as_mut())
}
}
}
pub struct GridSetter<CT: RowTemp, RT: RowTemp, S: GridStorage> {
w_offsets: CT,
h_offsets: RT,
pos: Coord,
_s: PhantomData<S>,
}
impl<CT: RowTemp, RT: RowTemp, S: GridStorage> GridSetter<CT, RT, S> {
pub fn new(rect: Rect, dim: GridDimensions, storage: &mut S) -> Self {
let (cols, rows) = (dim.cols.cast(), dim.rows.cast());
let mut w_offsets = CT::default();
w_offsets.set_len(cols);
let mut h_offsets = RT::default();
h_offsets.set_len(rows);
storage.set_dims(cols, rows);
if cols > 0 {
let (widths, rules) = storage.widths_and_rules();
let target = rect.size.0;
SizeRules::solve_seq(widths, rules, target);
w_offsets.as_mut()[0] = 0;
for i in 1..w_offsets.as_mut().len() {
let i1 = i - 1;
let m1 = storage.width_rules()[i1].margins_i32().1;
let m0 = storage.width_rules()[i].margins_i32().0;
w_offsets.as_mut()[i] = w_offsets.as_mut()[i1] + storage.widths()[i1] + m1.max(m0);
}
}
if rows > 0 {
let (heights, rules) = storage.heights_and_rules();
let target = rect.size.1;
SizeRules::solve_seq(heights, rules, target);
h_offsets.as_mut()[0] = 0;
for i in 1..h_offsets.as_mut().len() {
let i1 = i - 1;
let m1 = storage.height_rules()[i1].margins_i32().1;
let m0 = storage.height_rules()[i].margins_i32().0;
h_offsets.as_mut()[i] = h_offsets.as_mut()[i1] + storage.heights()[i1] + m1.max(m0);
}
}
GridSetter {
w_offsets,
h_offsets,
pos: rect.pos,
_s: Default::default(),
}
}
}
impl<CT: RowTemp, RT: RowTemp, S: GridStorage> RulesSetter for GridSetter<CT, RT, S> {
type Storage = S;
type ChildInfo = GridChildInfo;
fn child_rect(&mut self, storage: &mut Self::Storage, info: Self::ChildInfo) -> Rect {
let x = self.w_offsets.as_mut()[usize::conv(info.col)];
let y = self.h_offsets.as_mut()[usize::conv(info.row)];
let pos = self.pos + Offset(x, y);
let i1 = usize::conv(info.col_end) - 1;
let w = storage.widths()[i1] + self.w_offsets.as_mut()[i1]
- self.w_offsets.as_mut()[usize::conv(info.col)];
let i1 = usize::conv(info.row_end) - 1;
let h = storage.heights()[i1] + self.h_offsets.as_mut()[i1]
- self.h_offsets.as_mut()[usize::conv(info.row)];
let size = Size(w, h);
Rect { pos, size }
}
fn maximal_rect_of(&mut self, _: &mut Self::Storage, _: Self::ChildInfo) -> Rect {
unimplemented!()
}
}