Skip to content

Commit

Permalink
Merge pull request #304 from kas-gui/work2
Browse files Browse the repository at this point in the history
Column before row; make_layout for grids
  • Loading branch information
dhardy committed Apr 12, 2022
2 parents 2ac577d + e03ad35 commit 58acfd4
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 194 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ keywords = ["gui"]
categories = ["gui"]
repository = "https://github.com/kas-gui/kas"
exclude = ["/examples"]
rust-version = "1.56"

[package.metadata.docs.rs]
features = ["nightly"]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ Getting started

### Dependencies

KAS requires a recent [Rust] compiler. Currently, version 1.56 or greater is
required. Using the **nightly** channel does have a few advantages:
KAS requires a [Rust] compiler, version (MSRV) 1.56 or greater.
Using the **nightly** channel does have a few advantages:

- Procedural macros can only emit warnings using nightly `rustc`.
missed without nightly rustc, hence **nightly is recommended for development**.
Expand Down
54 changes: 27 additions & 27 deletions crates/kas-core/src/layout/grid_solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,50 +33,50 @@ impl<T: Clone + Default> DefaultWithLen for Vec<T> {
/// Grid dimensions
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct GridDimensions {
pub rows: u32,
pub cols: u32,
pub row_spans: u32,
pub col_spans: u32,
pub rows: u32,
pub row_spans: u32,
}

/// Per-child information
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct GridChildInfo {
/// Row index (first row when in a span)
pub row: u32,
/// One-past-last index of row span (`row_end = row + 1` without span)
pub row_end: u32,
/// Column index (first column when in a span)
pub col: u32,
/// One-past-last index of column span (`col_end = col + 1` without span)
pub col_end: u32,
/// Row index (first row when in a span)
pub row: u32,
/// One-past-last index of row span (`row_end = row + 1` without span)
pub row_end: u32,
}

impl GridChildInfo {
/// Construct from row and column
pub fn new(row: u32, col: u32) -> Self {
pub fn new(col: u32, row: u32) -> Self {
GridChildInfo {
row,
row_end: row + 1,
col,
col_end: col + 1,
row,
row_end: row + 1,
}
}
}

/// A [`RulesSolver`] for grids supporting cell-spans
///
/// This implementation relies on the caller to provide storage for solver data.
pub struct GridSolver<RSR, CSR, S: GridStorage> {
pub struct GridSolver<CSR, RSR, S: GridStorage> {
axis: AxisInfo,
row_spans: RSR,
col_spans: CSR,
next_row_span: usize,
row_spans: RSR,
next_col_span: usize,
next_row_span: usize,
_s: PhantomData<S>,
}

impl<RSR: DefaultWithLen, CSR: DefaultWithLen, S: GridStorage> GridSolver<RSR, CSR, S> {
impl<CSR: DefaultWithLen, RSR: DefaultWithLen, S: GridStorage> GridSolver<CSR, RSR, S> {
/// Construct.
///
/// Argument order is consistent with other [`RulesSolver`]s.
Expand All @@ -85,17 +85,17 @@ impl<RSR: DefaultWithLen, CSR: DefaultWithLen, S: GridStorage> GridSolver<RSR, C
/// - `dim`: grid dimensions
/// - `storage`: reference to persistent storage
pub fn new(axis: AxisInfo, dim: GridDimensions, storage: &mut S) -> Self {
let row_spans = RSR::default_with_len(dim.row_spans.cast());
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.rows.cast(), dim.cols.cast());
storage.set_dims(dim.cols.cast(), dim.rows.cast());

let mut solver = GridSolver {
axis,
row_spans,
col_spans,
next_row_span: 0,
row_spans,
next_col_span: 0,
next_row_span: 0,
_s: Default::default(),
};
solver.prepare(storage);
Expand Down Expand Up @@ -125,10 +125,10 @@ impl<RSR: DefaultWithLen, CSR: DefaultWithLen, S: GridStorage> GridSolver<RSR, C
}
}

impl<RSR, CSR, S: GridStorage> RulesSolver for GridSolver<RSR, CSR, S>
impl<CSR, RSR, S: GridStorage> RulesSolver for GridSolver<CSR, RSR, S>
where
RSR: AsRef<[(SizeRules, u32, u32)]> + AsMut<[(SizeRules, u32, u32)]>,
CSR: AsRef<[(SizeRules, u32, u32)]> + AsMut<[(SizeRules, u32, u32)]>,
RSR: AsRef<[(SizeRules, u32, u32)]> + AsMut<[(SizeRules, u32, u32)]>,
{
type Storage = S;
type ChildInfo = GridChildInfo;
Expand Down Expand Up @@ -259,14 +259,14 @@ where
}

/// A [`RulesSetter`] for grids supporting cell-spans
pub struct GridSetter<RT: RowTemp, CT: RowTemp, S: GridStorage> {
h_offsets: RT,
pub struct GridSetter<CT: RowTemp, RT: RowTemp, S: GridStorage> {
w_offsets: CT,
h_offsets: RT,
pos: Coord,
_s: PhantomData<S>,
}

impl<RT: RowTemp, CT: RowTemp, S: GridStorage> GridSetter<RT, CT, S> {
impl<CT: RowTemp, RT: RowTemp, S: GridStorage> GridSetter<CT, RT, S> {
/// Construct
///
/// Argument order is consistent with other [`RulesSetter`]s.
Expand All @@ -276,13 +276,13 @@ impl<RT: RowTemp, CT: RowTemp, S: GridStorage> GridSetter<RT, CT, S> {
/// - `align`: alignment hints
/// - `storage`: access to the solver's storage
pub fn new(rect: Rect, dim: GridDimensions, align: AlignHints, storage: &mut S) -> Self {
let (rows, cols) = (dim.rows.cast(), dim.cols.cast());
let mut h_offsets = RT::default();
h_offsets.set_len(rows);
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(rows, cols);
storage.set_dims(cols, rows);

if cols > 0 {
let align = align.horiz.unwrap_or(Align::Default);
Expand Down Expand Up @@ -345,7 +345,7 @@ impl<RT: RowTemp, CT: RowTemp, S: GridStorage> GridSetter<RT, CT, S> {
}
}

impl<RT: RowTemp, CT: RowTemp, S: GridStorage> RulesSetter for GridSetter<RT, CT, S> {
impl<CT: RowTemp, RT: RowTemp, S: GridStorage> RulesSetter for GridSetter<CT, RT, S> {
type Storage = S;
type ChildInfo = GridChildInfo;

Expand Down
115 changes: 53 additions & 62 deletions crates/kas-core/src/layout/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//! Layout solver — storage

use super::SizeRules;
use kas_macros::impl_scope;
use std::any::Any;

/// Master trait over storage types
Expand Down Expand Up @@ -152,7 +153,7 @@ where
/// Details are hidden (for internal use only).
pub trait GridStorage: sealed::Sealed + Clone {
#[doc(hidden)]
fn set_dims(&mut self, rows: usize, cols: usize);
fn set_dims(&mut self, cols: usize, rows: usize);

#[doc(hidden)]
fn width_rules(&mut self) -> &mut [SizeRules] {
Expand Down Expand Up @@ -183,70 +184,60 @@ pub trait GridStorage: sealed::Sealed + Clone {
fn heights_rules_total(&mut self) -> (&mut [i32], &mut [SizeRules], SizeRules);
}

/// Fixed-length grid storage
///
/// Uses const-generics arguments `R, C` (the number of rows and columns).
#[derive(Clone, Debug)]
pub struct FixedGridStorage<const R: usize, const C: usize> {
width_rules: [SizeRules; C],
height_rules: [SizeRules; R],
width_total: SizeRules,
height_total: SizeRules,
widths: [i32; C],
heights: [i32; R],
}

impl<const R: usize, const C: usize> Default for FixedGridStorage<R, C> {
fn default() -> Self {
FixedGridStorage {
width_rules: [SizeRules::default(); C],
height_rules: [SizeRules::default(); R],
width_total: SizeRules::default(),
height_total: SizeRules::default(),
widths: [0; C],
heights: [0; R],
impl_scope! {
/// Fixed-length grid storage
///
/// Uses const-generics arguments `R, C` (the number of rows and columns).
#[impl_default]
#[derive(Clone, Debug)]
pub struct FixedGridStorage<const C: usize, const R: usize> {
width_rules: [SizeRules; C] = [SizeRules::default(); C],
height_rules: [SizeRules; R] = [SizeRules::default(); R],
width_total: SizeRules,
height_total: SizeRules,
widths: [i32; C] = [0; C],
heights: [i32; R] = [0; R],
}

impl Storage for Self {
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
}

impl<const R: usize, const C: usize> Storage for FixedGridStorage<R, C> {
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}

impl<const R: usize, const C: usize> GridStorage for FixedGridStorage<R, C> {
fn set_dims(&mut self, rows: usize, cols: usize) {
assert_eq!(self.width_rules.as_ref().len(), cols);
assert_eq!(self.height_rules.as_ref().len(), rows);
assert_eq!(self.widths.len(), cols);
assert_eq!(self.heights.len(), rows);
}
impl GridStorage for Self {
fn set_dims(&mut self, cols: usize, rows: usize) {
assert_eq!(self.width_rules.as_ref().len(), cols);
assert_eq!(self.height_rules.as_ref().len(), rows);
assert_eq!(self.widths.len(), cols);
assert_eq!(self.heights.len(), rows);
}

#[doc(hidden)]
fn set_width_total(&mut self, total: SizeRules) {
self.width_total = total;
}
#[doc(hidden)]
fn set_height_total(&mut self, total: SizeRules) {
self.height_total = total;
}
#[doc(hidden)]
fn set_width_total(&mut self, total: SizeRules) {
self.width_total = total;
}
#[doc(hidden)]
fn set_height_total(&mut self, total: SizeRules) {
self.height_total = total;
}

#[doc(hidden)]
fn widths_rules_total(&mut self) -> (&mut [i32], &mut [SizeRules], SizeRules) {
(
self.widths.as_mut(),
self.width_rules.as_mut(),
self.width_total,
)
}
#[doc(hidden)]
fn heights_rules_total(&mut self) -> (&mut [i32], &mut [SizeRules], SizeRules) {
(
self.heights.as_mut(),
self.height_rules.as_mut(),
self.height_total,
)
#[doc(hidden)]
fn widths_rules_total(&mut self) -> (&mut [i32], &mut [SizeRules], SizeRules) {
(
self.widths.as_mut(),
self.width_rules.as_mut(),
self.width_total,
)
}
#[doc(hidden)]
fn heights_rules_total(&mut self) -> (&mut [i32], &mut [SizeRules], SizeRules) {
(
self.heights.as_mut(),
self.height_rules.as_mut(),
self.height_total,
)
}
}
}

Expand All @@ -268,7 +259,7 @@ impl Storage for DynGridStorage {
}

impl GridStorage for DynGridStorage {
fn set_dims(&mut self, rows: usize, cols: usize) {
fn set_dims(&mut self, cols: usize, rows: usize) {
self.width_rules.resize(cols, SizeRules::EMPTY);
self.height_rules.resize(rows, SizeRules::EMPTY);
self.widths.resize(cols, 0);
Expand Down Expand Up @@ -308,6 +299,6 @@ mod sealed {
impl Sealed for super::DynRowStorage {}
impl Sealed for Vec<i32> {}
impl<const L: usize> Sealed for [i32; L] {}
impl<const R: usize, const C: usize> Sealed for super::FixedGridStorage<R, C> {}
impl<const C: usize, const R: usize> Sealed for super::FixedGridStorage<C, R> {}
impl Sealed for super::DynGridStorage {}
}
16 changes: 14 additions & 2 deletions crates/kas-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ pub fn make_widget(input: TokenStream) -> TokenStream {
/// > &nbsp;&nbsp; `self` `.` _Member_ | _Expr_
/// >
/// > _ListPre_ :\
/// > &nbsp;&nbsp; `column` | `row` | `list` `(` _Direction_ `)`
/// > &nbsp;&nbsp; `column` | `row` | `aligned_column` | `aligned_row` | `list` `(` _Direction_ `)`
/// >
/// > _List_ :\
/// > &nbsp;&nbsp; _ListPre_ `:` `*` | (`[` _Layout_ `]`)
Expand All @@ -470,8 +470,11 @@ pub fn make_widget(input: TokenStream) -> TokenStream {
/// > &nbsp;&nbsp; `grid` `:` `{` _GridCell_* `}`
/// >
/// > _GridCell_ :\
/// > &nbsp;&nbsp; _Range_ `,` _Range_ `:` _Layout_
/// > &nbsp;&nbsp; _CellRange_ `,` _CellRange_ `:` _Layout_
/// >
/// > _CellRange_ :\
/// > &nbsp;&nbsp; _LitInt_ ( `..` `+`? _LitInt_ )?
///
/// > _Frame_ :\
/// > &nbsp;&nbsp; `frame` `(` _Layout_ `)`
///
Expand All @@ -485,9 +488,18 @@ pub fn make_widget(input: TokenStream) -> TokenStream {
/// respectively. Glob syntax is allowed: `row: *` uses all children in a row
/// layout.
///
/// `aligned_column` and `aligned_row` use restricted list syntax (items must
/// be `row` or `column` respectively; glob syntax not allowed), but build a
/// grid layout. Essentially, they are syntax sugar for simple table layouts.
///
/// _Slice_ is a variant of _List_ over a single struct field, supporting
/// `AsMut<W>` for some widget type `W`.
///
/// A _Grid_ is an aligned two-dimensional layout supporting item spans.
/// Contents are declared as a collection of cells. Cell location is specified
/// like `0, 1` (that is, col=0, row=1) with spans specified like `0..2, 1`
/// (thus cols={0, 1}, row=1) or `2..+2, 1` (cols={2,3}, row=1).
///
/// _Member_ is a field name (struct) or number (tuple struct).
///
/// # Example
Expand Down
Loading

0 comments on commit 58acfd4

Please sign in to comment.