Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Column before row; make_layout for grids #304

Merged
merged 7 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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