diff --git a/Cargo.toml b/Cargo.toml index c8048befa..dcffd3083 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/README.md b/README.md index 7ad00adda..cf028653f 100644 --- a/README.md +++ b/README.md @@ -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**. diff --git a/crates/kas-core/src/layout/grid_solver.rs b/crates/kas-core/src/layout/grid_solver.rs index 49bf827fb..eb93b0e9a 100644 --- a/crates/kas-core/src/layout/grid_solver.rs +++ b/crates/kas-core/src/layout/grid_solver.rs @@ -33,33 +33,33 @@ impl DefaultWithLen for Vec { /// 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, } } } @@ -67,16 +67,16 @@ impl GridChildInfo { /// A [`RulesSolver`] for grids supporting cell-spans /// /// This implementation relies on the caller to provide storage for solver data. -pub struct GridSolver { +pub struct GridSolver { 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, } -impl GridSolver { +impl GridSolver { /// Construct. /// /// Argument order is consistent with other [`RulesSolver`]s. @@ -85,17 +85,17 @@ impl GridSolver 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); @@ -125,10 +125,10 @@ impl GridSolver RulesSolver for GridSolver +impl RulesSolver for GridSolver 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; @@ -259,14 +259,14 @@ where } /// A [`RulesSetter`] for grids supporting cell-spans -pub struct GridSetter { - h_offsets: RT, +pub struct GridSetter { w_offsets: CT, + h_offsets: RT, pos: Coord, _s: PhantomData, } -impl GridSetter { +impl GridSetter { /// Construct /// /// Argument order is consistent with other [`RulesSetter`]s. @@ -276,13 +276,13 @@ impl GridSetter { /// - `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); @@ -345,7 +345,7 @@ impl GridSetter { } } -impl RulesSetter for GridSetter { +impl RulesSetter for GridSetter { type Storage = S; type ChildInfo = GridChildInfo; diff --git a/crates/kas-core/src/layout/storage.rs b/crates/kas-core/src/layout/storage.rs index ef896308b..815e52afc 100644 --- a/crates/kas-core/src/layout/storage.rs +++ b/crates/kas-core/src/layout/storage.rs @@ -6,6 +6,7 @@ //! Layout solver — storage use super::SizeRules; +use kas_macros::impl_scope; use std::any::Any; /// Master trait over storage types @@ -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] { @@ -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 { - width_rules: [SizeRules; C], - height_rules: [SizeRules; R], - width_total: SizeRules, - height_total: SizeRules, - widths: [i32; C], - heights: [i32; R], -} - -impl Default for FixedGridStorage { - 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 { + 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 Storage for FixedGridStorage { - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} -impl GridStorage for FixedGridStorage { - 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, + ) + } } } @@ -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); @@ -308,6 +299,6 @@ mod sealed { impl Sealed for super::DynRowStorage {} impl Sealed for Vec {} impl Sealed for [i32; L] {} - impl Sealed for super::FixedGridStorage {} + impl Sealed for super::FixedGridStorage {} impl Sealed for super::DynGridStorage {} } diff --git a/crates/kas-macros/src/lib.rs b/crates/kas-macros/src/lib.rs index 91f4604ce..4e9c780f4 100644 --- a/crates/kas-macros/src/lib.rs +++ b/crates/kas-macros/src/lib.rs @@ -458,7 +458,7 @@ pub fn make_widget(input: TokenStream) -> TokenStream { /// >    `self` `.` _Member_ | _Expr_ /// > /// > _ListPre_ :\ -/// >    `column` | `row` | `list` `(` _Direction_ `)` +/// >    `column` | `row` | `aligned_column` | `aligned_row` | `list` `(` _Direction_ `)` /// > /// > _List_ :\ /// >    _ListPre_ `:` `*` | (`[` _Layout_ `]`) @@ -470,8 +470,11 @@ pub fn make_widget(input: TokenStream) -> TokenStream { /// >    `grid` `:` `{` _GridCell_* `}` /// > /// > _GridCell_ :\ -/// >    _Range_ `,` _Range_ `:` _Layout_ +/// >    _CellRange_ `,` _CellRange_ `:` _Layout_ /// > +/// > _CellRange_ :\ +/// >    _LitInt_ ( `..` `+`? _LitInt_ )? +/// /// > _Frame_ :\ /// >    `frame` `(` _Layout_ `)` /// @@ -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` 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 diff --git a/crates/kas-macros/src/make_layout.rs b/crates/kas-macros/src/make_layout.rs index b26cf3283..6f8315fd8 100644 --- a/crates/kas-macros/src/make_layout.rs +++ b/crates/kas-macros/src/make_layout.rs @@ -14,7 +14,6 @@ mod kw { use syn::custom_keyword; custom_keyword!(align); - custom_keyword!(col); custom_keyword!(column); custom_keyword!(row); custom_keyword!(right); @@ -31,6 +30,8 @@ mod kw { custom_keyword!(default); custom_keyword!(top); custom_keyword!(bottom); + custom_keyword!(aligned_column); + custom_keyword!(aligned_row); } pub struct Input { @@ -89,66 +90,78 @@ enum Align { #[derive(Debug, Default)] struct GridDimensions { - rows: u32, cols: u32, - row_spans: u32, col_spans: u32, + rows: u32, + row_spans: u32, } -#[derive(Debug)] + +#[derive(Copy, Clone, Debug)] struct CellInfo { - row: u32, - row_end: u32, col: u32, col_end: u32, + row: u32, + row_end: u32, +} + +impl CellInfo { + fn new(col: u32, row: u32) -> Self { + CellInfo { + col, + col_end: col + 1, + row, + row_end: row + 1, + } + } } -impl Parse for CellInfo { - fn parse(input: ParseStream) -> Result { - let row = input.parse::()?.base10_parse()?; - let row_end = if input.peek(Token![..]) { - let _ = input.parse::(); - let lit = input.parse::()?; - let end = lit.base10_parse()?; - if row >= end { - return Err(Error::new(lit.span(), format!("expected value > {}", row))); - } - end - } else { - row + 1 - }; - let _ = input.parse::()?; +fn parse_cell_info(input: ParseStream) -> Result { + fn parse_end(input: ParseStream, start: u32) -> Result { + if input.parse::().is_ok() { + if input.parse::().is_ok() { + return Ok(start + input.parse::()?.base10_parse::()?); + } - let col = input.parse::()?.base10_parse()?; - let col_end = if input.peek(Token![..]) { - let _ = input.parse::(); let lit = input.parse::()?; let end = lit.base10_parse()?; - if col >= end { - return Err(Error::new(lit.span(), format!("expected value > {}", col))); + if start >= end { + return Err(Error::new( + lit.span(), + format!("expected value > {}", start), + )); } - end + Ok(end) } else { - col + 1 - }; - - Ok(CellInfo { - row, - row_end, - col, - col_end, - }) + Ok(start + 1) + } } + + let col = input.parse::()?.base10_parse()?; + let col_end = parse_end(input, col)?; + + let _ = input.parse::()?; + + let row = input.parse::()?.base10_parse()?; + let row_end = parse_end(input, row)?; + + Ok(CellInfo { + row, + row_end, + col, + col_end, + }) } + impl GridDimensions { fn update(&mut self, cell: &CellInfo) { - self.rows = self.rows.max(cell.row_end); self.cols = self.cols.max(cell.col_end); - if cell.row_end - cell.row > 1 { - self.row_spans += 1; - } if cell.col_end - cell.col > 1 { self.col_spans += 1; } + self.rows = self.rows.max(cell.row_end); + if cell.row_end - cell.row > 1 { + self.row_spans += 1; + } } } @@ -215,6 +228,14 @@ impl Parse for Layout { let _: Token![:] = input.parse()?; let list = parse_layout_list(input)?; Ok(Layout::List(dir, list)) + } else if lookahead.peek(kw::aligned_column) { + let _: kw::aligned_column = input.parse()?; + let _: Token![:] = input.parse()?; + Ok(parse_grid_as_list_of_lists::(input, true)?) + } else if lookahead.peek(kw::aligned_row) { + let _: kw::aligned_row = input.parse()?; + let _: Token![:] = input.parse()?; + Ok(parse_grid_as_list_of_lists::(input, false)?) } else if lookahead.peek(kw::slice) { let _: kw::slice = input.parse()?; let inner; @@ -293,6 +314,56 @@ fn parse_layout_list(input: ParseStream) -> Result { } } +fn parse_grid_as_list_of_lists(input: ParseStream, row_major: bool) -> Result { + let inner; + let _ = bracketed!(inner in input); + + let (mut col, mut row) = (0, 0); + let mut dim = GridDimensions::default(); + let mut cells = vec![]; + + while !inner.is_empty() { + let _ = inner.parse::()?; + let _ = inner.parse::()?; + + let inner2; + let _ = bracketed!(inner2 in inner); + + while !inner2.is_empty() { + let info = CellInfo::new(col, row); + dim.update(&info); + let layout = inner2.parse()?; + cells.push((info, layout)); + + if inner2.is_empty() { + break; + } + let _: Token![,] = inner2.parse()?; + + if row_major { + col += 1; + } else { + row += 1; + } + } + + if inner.is_empty() { + break; + } + let _: Token![,] = inner.parse()?; + + if row_major { + col = 0; + row += 1; + } else { + row = 0; + col += 1; + } + } + + Ok(Layout::Grid(dim, cells)) +} + fn parse_grid(input: ParseStream) -> Result { let inner; let _ = braced!(inner in input); @@ -300,7 +371,7 @@ fn parse_grid(input: ParseStream) -> Result { let mut dim = GridDimensions::default(); let mut cells = vec![]; while !inner.is_empty() { - let info = inner.parse()?; + let info = parse_cell_info(&inner)?; dim.update(&info); let _: Token![:] = inner.parse()?; let layout = inner.parse()?; @@ -367,13 +438,13 @@ impl quote::ToTokens for Direction { impl quote::ToTokens for GridDimensions { fn to_tokens(&self, toks: &mut Toks) { - let (rows, cols) = (self.rows, self.cols); - let (row_spans, col_spans) = (self.row_spans, self.col_spans); + let (cols, rows) = (self.cols, self.rows); + let (col_spans, row_spans) = (self.col_spans, self.row_spans); toks.append_all(quote! { layout::GridDimensions { - rows: #rows, cols: #cols, - row_spans: #row_spans, col_spans: #col_spans, + rows: #rows, + row_spans: #row_spans, } }); } } @@ -478,25 +549,25 @@ impl Layout { quote! { layout::Layout::slice(&mut #expr, #dir, #data) } } Layout::Grid(dim, cells) => { - let (rows, cols) = (dim.rows as usize, dim.cols as usize); + let (cols, rows) = (dim.cols as usize, dim.rows as usize); let data = quote! { { - let (data, next) = _chain.storage::>(); + let (data, next) = _chain.storage::>(); _chain = next; data } }; let mut items = Toks::new(); for item in cells { - let (row, row_end) = (item.0.row, item.0.row_end); let (col, col_end) = (item.0.col, item.0.col_end); + let (row, row_end) = (item.0.row, item.0.row_end); let layout = item.1.generate::>(None)?; items.append_all(quote! { ( layout::GridChildInfo { - row: #row, - row_end: #row_end, col: #col, col_end: #col_end, + row: #row, + row_end: #row_end, }, #layout, ), diff --git a/crates/kas-widgets/src/grid.rs b/crates/kas-widgets/src/grid.rs index bb7f45e5c..d5da69f98 100644 --- a/crates/kas-widgets/src/grid.rs +++ b/crates/kas-widgets/src/grid.rs @@ -215,8 +215,8 @@ impl<'a, W: Widget> GridBuilder<'a, W> { /// /// The child is added to the end of the "list", thus appears last in /// navigation order. - pub fn push_cell(&mut self, row: u32, col: u32, widget: W) { - let info = GridChildInfo::new(row, col); + pub fn push_cell(&mut self, col: u32, row: u32, widget: W) { + let info = GridChildInfo::new(col, row); self.push(info, widget); } @@ -225,30 +225,30 @@ impl<'a, W: Widget> GridBuilder<'a, W> { /// The child is added to the end of the "list", thus appears last in /// navigation order. #[must_use] - pub fn with_cell(self, row: u32, col: u32, widget: W) -> Self { - self.with_cell_span(row, col, 1, 1, widget) + pub fn with_cell(self, col: u32, row: u32, widget: W) -> Self { + self.with_cell_span(col, row, 1, 1, widget) } /// Add a child widget to the given cell, with spans /// - /// Parameters `row_span` and `col_span` are the number of rows/columns + /// Parameters `col_span` and `row_span` are the number of columns/rows /// spanned and should each be at least 1. /// /// The child is added to the end of the "list", thus appears last in /// navigation order. - pub fn push_cell_span(&mut self, row: u32, col: u32, row_span: u32, col_span: u32, widget: W) { + pub fn push_cell_span(&mut self, col: u32, row: u32, col_span: u32, row_span: u32, widget: W) { let info = GridChildInfo { - row, - row_end: row + row_span, col, col_end: col + col_span, + row, + row_end: row + row_span, }; self.push(info, widget); } /// Add a child widget to the given cell, with spans, builder style /// - /// Parameters `row_span` and `col_span` are the number of rows/columns + /// Parameters `col_span` and `row_span` are the number of columns/rows /// spanned and should each be at least 1. /// /// The child is added to the end of the "list", thus appears last in @@ -256,13 +256,13 @@ impl<'a, W: Widget> GridBuilder<'a, W> { #[must_use] pub fn with_cell_span( mut self, - row: u32, col: u32, - row_span: u32, + row: u32, col_span: u32, + row_span: u32, widget: W, ) -> Self { - self.push_cell_span(row, col, row_span, col_span, widget); + self.push_cell_span(col, row, col_span, row_span, widget); self } @@ -323,7 +323,7 @@ impl<'a, W: Widget> GridBuilder<'a, W> { } /// Get the first index of a child occupying the given cell, if any - pub fn find_child_cell(&self, row: u32, col: u32) -> Option { + pub fn find_child_cell(&self, col: u32, row: u32) -> Option { for (i, (info, _)) in self.0.iter().enumerate() { if info.col <= col && col < info.col_end && info.row <= row && row < info.row_end { return Some(i); diff --git a/crates/kas-widgets/src/view/matrix_view.rs b/crates/kas-widgets/src/view/matrix_view.rs index 134ede625..76a5e949e 100644 --- a/crates/kas-widgets/src/view/matrix_view.rs +++ b/crates/kas-widgets/src/view/matrix_view.rs @@ -95,7 +95,7 @@ impl_scope! { data_ver: 0, widgets: Default::default(), align_hints: Default::default(), - ideal_len: Dim { rows: 3, cols: 5 }, + ideal_len: Dim { cols: 3, rows: 5 }, alloc_len: Dim::default(), cur_len: 0, child_size_min: Size::ZERO, @@ -255,8 +255,8 @@ impl_scope! { /// This affects the (ideal) size request and whether children are sized /// according to their ideal or minimum size but not the minimum size. #[must_use] - pub fn with_num_visible(mut self, rows: i32, cols: i32) -> Self { - self.ideal_len = Dim { rows, cols }; + pub fn with_num_visible(mut self, cols: i32, rows: i32) -> Self { + self.ideal_len = Dim { cols, rows }; self } diff --git a/examples/calculator.rs b/examples/calculator.rs index bcf69bb2f..4beeec96f 100644 --- a/examples/calculator.rs +++ b/examples/calculator.rs @@ -29,13 +29,13 @@ fn main() -> kas::shell::Result<()> { let buttons = make_widget! { #[widget{ layout = grid: { - 0, 0: self.b_clear; 0, 1: self.b_div; 0, 2: self.b_mul; 0, 3: self.b_sub; - 1, 0: self.b7; 1, 1: self.b8; 1, 2: self.b9; - 1..3, 3: align(stretch): self.b_add; - 2, 0: self.b4; 2, 1: self.b5; 2, 2: self.b6; - 3, 0: self.b1; 3, 1: self.b2; 3, 2: self.b3; - 3..5, 3: align(stretch): self.b_eq; - 4, 0..2: self.b0; 4, 2: self.b_dot; + 0, 0: self.b_clear; 1, 0: self.b_div; 2, 0: self.b_mul; 3, 0: self.b_sub; + 0, 1: self.b7; 1, 1: self.b8; 2, 1: self.b9; + 3, 1..3: self.b_add; + 0, 2: self.b4; 1, 2: self.b5; 2, 2: self.b6; + 0, 3: self.b1; 1, 3: self.b2; 2, 3: self.b3; + 3, 3..5: self.b_eq; + 0..2, 4: self.b0; 2, 4: self.b_dot; }; msg = Key; }] diff --git a/examples/gallery.rs b/examples/gallery.rs index 239482b81..6afe433eb 100644 --- a/examples/gallery.rs +++ b/examples/gallery.rs @@ -48,8 +48,8 @@ impl_scope! { #[derive(Debug)] #[widget{ layout = grid: { - 0, 0..3: self.edit; - 1, 0: self.fill; 1, 1: self.cancel; 1, 2: self.save; + 0..3, 0: self.edit; + 0, 1: self.fill; 1, 1: self.cancel; 2, 1: self.save; }; }] struct TextEditPopup { @@ -221,24 +221,22 @@ fn main() -> Result<(), Box> { let radio = RadioBoxGroup::default(); let widgets = make_widget! { - // TODO: this would be better expressed with a column layout, though we - // want better alignment controls first (which are also needed for menus). #[widget{ - layout = grid: { - 0, 0: self.sll; 0, 1: self.sl; - 1, 0: self.ebl; 1, 1: self.eb; - 2, 0: self.tbl; 2, 1: self.tb; - 3, 0: self.bil; 3, 1: self.bi; - 4, 0: self.cbl; 4, 1: self.cb; - 5, 0: self.rbl; 5, 1: self.rb; - 6, 0: self.rb2l; 6, 1: self.rb2; - 7, 0: self.cbbl; 7, 1: self.cbb; - 8, 0: self.sdl; 8, 1: self.sd; - 9, 0: self.scl; 9, 1: self.sc; - 10, 0: self.pgl; 10, 1: self.pg; - 11, 0: self.svl; 11, 1: align(center): self.sv; - 12, 0: self.pul; 12, 1: self.pu; - }; + layout = aligned_column: [ + row: [self.sll, self.sl], + row: [self.ebl, self.eb], + row: [self.tbl, self.tb], + row: [self.bil, self.bi], + row: [self.cbl, self.cb], + row: [self.rbl, self.rb], + row: [self.rb2l, self.rb2], + row: [self.cbbl, self.cbb], + row: [self.sdl, self.sd], + row: [self.scl, self.sc], + row: [self.pgl, self.pg], + row: [self.svl, align(center): self.sv], + row: [self.pul, self.pu], + ]; msg = Item; }] struct { diff --git a/examples/layout.rs b/examples/layout.rs index 41941e9ba..fc1242101 100644 --- a/examples/layout.rs +++ b/examples/layout.rs @@ -20,12 +20,12 @@ fn main() -> kas::shell::Result<()> { make_widget! { #[widget{ layout = grid: { - 0, 1: self.title; - 0, 2: self.check; - 1, 0..3: self.lipsum; - 2, 0: align(center): self.abc; - 2..4, 1..3: align(stretch): self.crasit; - 3, 0: self.edit; + 1, 0: self.title; + 2, 0: self.check; + 0..3, 1: self.lipsum; + 0, 2: align(center): self.abc; + 1..3, 2..4: align(stretch): self.crasit; + 0, 3: self.edit; }; msg = VoidMsg; }] diff --git a/examples/mandlebrot/mandlebrot.rs b/examples/mandlebrot/mandlebrot.rs index 022d1ac8b..647463bb9 100644 --- a/examples/mandlebrot/mandlebrot.rs +++ b/examples/mandlebrot/mandlebrot.rs @@ -430,9 +430,9 @@ impl_scope! { #[derive(Debug)] #[widget{ layout = grid: { - 0, 0..2: self.label; - 1, 0: align(center): self.iters; - 2, 0: self.slider; + 0..2, 0: self.label; + 0, 1: align(center): self.iters; + 0, 2: self.slider; 1..3, 1..3: self.mbrot; }; msg = event::VoidMsg;