Skip to content

Commit

Permalink
Replace margins! layout macro with adapter widget
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardy committed Jan 24, 2024
1 parent 0f94ba4 commit 2d720e1
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 140 deletions.
43 changes: 1 addition & 42 deletions crates/kas-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ pub fn impl_scope(input: TokenStream) -> TokenStream {
/// implementation of `Events::nav_next`, with a couple of exceptions
/// (where macro-time analysis is insufficient to implement this method).
///
/// > [_Column_](macro@column), [_Row_](macro@row), [_List_](macro@list), [_AlignedColumn_](macro@aligned_column), [_AlignedRow_](macro@aligned_row), [_Grid_](macro@grid), [_Float_](macro@float), [_Margins_](macro@margins) :\
/// > [_Column_](macro@column), [_Row_](macro@row), [_List_](macro@list), [_AlignedColumn_](macro@aligned_column), [_AlignedRow_](macro@aligned_row), [_Grid_](macro@grid), [_Float_](macro@float) :\
/// >    These stand-alone macros are explicitly supported in this position.\
/// >    Optionally, a _Storage_ specifier is supported immediately after the macro name, e.g.\
/// >    `column! 'storage_name ["one", "two"]`
Expand Down Expand Up @@ -609,47 +609,6 @@ pub fn aligned_row(input: TokenStream) -> TokenStream {
parse_macro_input!(input with make_layout::Tree::aligned_row).expand_layout("_AlignedRow")
}

/// Make a margin-adjustment widget wrapper
///
/// This is a small wrapper which adjusts the margins of its contents.
///
/// # Example
///
/// ```ignore
/// let a = kas::margins!(1.0 em, "abc");
/// let b = kas::margins!(vert = none, "abc");
/// ```
///
/// # Syntax
///
/// The macro takes one of two forms:
///
/// > _Margins_:\
/// >    `margins!` `(` _MarginSpec_ `,` _Layout_ `)`\
/// >    `margins!` `(` _MarginDirection_ `=` _MarginSpec_ `,` _Layout_ `)`\
/// >
/// > _MarginDirection_ :\
/// >    `horiz` | `horizontal` | `vert` | `vertical` | `left` | `right` | `top` | `bottom`
/// >
/// > _MarginSpec_ :\
/// >    ( _LitFloat_ `px` ) | ( _LitFloat_ `em` ) | `none` | `inner` | `tiny` | `small` | `large` | `text`
///
/// | _MarginSpec_ | Description (guide size; theme-specified sizes may vary and may not scale linearly) |
/// | --- | --- |
/// | `none` | No margin (`0px`) |
/// | `inner` | A very tiny theme-specified margin sometimes used to draw selection outlines (`1px`) |
/// | `tiny` | A very small theme-specified margin (`2px`) |
/// | `small` | A small theme-specified margin (`4px`) |
/// | `large`| A large theme-specified margin (`7px`) |
/// | `text` | Text-specific margins; often asymmetric |
/// | _LitFloat_ `em` (e.g. `1.2 em`) | Using the typographic unit Em (`1Em` is the text height, excluding ascender and descender) |
/// | _LitFloat_ `px` (e.g. `5.0 px`) | Using virtual pixels (affected by the scale factor) |
#[proc_macro_error]
#[proc_macro]
pub fn margins(input: TokenStream) -> TokenStream {
parse_macro_input!(input with make_layout::Tree::margins).expand_layout("_Margins")
}

/// Generate an anonymous struct which implements [`kas::Collection`]
///
/// Each item must be either a string literal (inferred as a static label) or a
Expand Down
89 changes: 2 additions & 87 deletions crates/kas-macros/src/make_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ mod kw {
custom_keyword!(aligned_column);
custom_keyword!(aligned_row);
custom_keyword!(float);
custom_keyword!(margins);
custom_keyword!(non_navigable);
custom_keyword!(px);
custom_keyword!(em);
Expand Down Expand Up @@ -327,12 +326,6 @@ impl Tree {
let stor = gen.next();
Ok(Tree(parse_grid(stor.into(), inner, &mut gen)?))
}

/// Parse margins (contents only)
pub fn margins(inner: ParseStream) -> Result<Self> {
let mut gen = NameGenerator::default();
Layout::margins_inner(inner, &mut gen).map(Tree)
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -383,7 +376,6 @@ impl GenerateItem for CellInfo {
#[derive(Debug)]
enum Layout {
Pack(Box<Layout>, Pack),
Margins(Box<Layout>, Directions, Toks),
Single(ExprMember),
Widget(Ident, Expr),
Frame(StorIdent, Box<Layout>, Expr),
Expand Down Expand Up @@ -554,14 +546,7 @@ impl Layout {

fn parse_macro_like(input: ParseStream, gen: &mut NameGenerator) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(kw::margins) {
let _ = input.parse::<kw::margins>()?;
let _: Token![!] = input.parse()?;

let inner;
let _ = parenthesized!(inner in input);
Self::margins_inner(&inner, gen)
} else if lookahead.peek(kw::frame) {
if lookahead.peek(kw::frame) {
let _: kw::frame = input.parse()?;
let _: Token![!] = input.parse()?;
let stor = gen.parse_or_next(input)?;
Expand Down Expand Up @@ -668,64 +653,6 @@ impl Layout {
Ok(Layout::Widget(ident, expr))
}
}

fn margins_inner(inner: ParseStream, gen: &mut NameGenerator) -> Result<Self> {
let mut dirs = Directions::all();
if inner.peek2(Token![=]) {
let ident = inner.parse::<Ident>()?;
dirs = match ident {
id if id == "horiz" || id == "horizontal" => Directions::LEFT | Directions::RIGHT,
id if id == "vert" || id == "vertical" => Directions::UP | Directions::DOWN,
id if id == "left" => Directions::LEFT,
id if id == "right" => Directions::RIGHT,
id if id == "top" => Directions::UP,
id if id == "bottom" => Directions::DOWN,
_ => return Err(Error::new(
ident.span(),
"expected one of: horiz, horizontal, vert, vertical, left, right, top, bottom",
)),
};
let _ = inner.parse::<Token![=]>()?;
}

let lookahead = inner.lookahead1();
let margins = if lookahead.peek(syn::LitFloat) {
let val = inner.parse::<syn::LitFloat>()?;
let lookahead = inner.lookahead1();
if lookahead.peek(kw::px) {
let _ = inner.parse::<kw::px>()?;
quote! { Px(#val) }
} else if lookahead.peek(kw::em) {
let _ = inner.parse::<kw::em>()?;
quote! { Em(#val) }
} else {
return Err(lookahead.error());
}
} else if lookahead.peek(Ident) {
let ident = inner.parse::<Ident>()?;
match ident {
id if id == "none" => quote! { None },
id if id == "inner" => quote! { Inner },
id if id == "tiny" => quote! { Tiny },
id if id == "small" => quote! { Small },
id if id == "large" => quote! { Large },
id if id == "text" => quote! { Text },
_ => {
return Err(Error::new(
ident.span(),
"expected one of: `none`, `inner`, `tiny`, `small`, `large`, `text` or a numeric value",
))
}
}
} else {
return Err(lookahead.error());
};

let _ = inner.parse::<Token![,]>()?;
let layout = Layout::parse(inner, gen)?;

Ok(Layout::Margins(Box::new(layout), dirs, margins))
}
}

fn parse_layout_list(input: ParseStream, gen: &mut NameGenerator) -> Result<VisitableList<()>> {
Expand Down Expand Up @@ -1015,9 +942,7 @@ impl ToTokens for MethodCall {
impl Layout {
fn append_fields(&self, fields: &mut StorageFields, children: &mut Vec<Child>, data_ty: &Type) {
match self {
Layout::Margins(layout, ..)
| Layout::NonNavigable(layout)
| Layout::MethodCall(layout, _) => {
Layout::NonNavigable(layout) | Layout::MethodCall(layout, _) => {
layout.append_fields(fields, children, data_ty);
}
Layout::Single(_) => (),
Expand Down Expand Up @@ -1132,14 +1057,6 @@ impl Layout {
pack.to_tokens(&mut tokens, core_path);
tokens
}
Layout::Margins(layout, dirs, selector) => {
let inner = layout.generate(core_path)?;
quote! { layout::Visitor::margins(
#inner,
::kas::dir::Directions::from_bits(#dirs).unwrap(),
::kas::theme::MarginStyle::#selector,
) }
}
Layout::Single(expr) => quote! {
layout::Visitor::single(&mut #expr)
},
Expand Down Expand Up @@ -1197,7 +1114,6 @@ impl Layout {
) -> std::result::Result<(), (Span, &'static str)> {
match self {
Layout::Pack(layout, _)
| Layout::Margins(layout, _, _)
| Layout::Frame(_, layout, _)
| Layout::MapAny(layout, _)
| Layout::MethodCall(layout, _) => layout.nav_next(children, output),
Expand Down Expand Up @@ -1261,7 +1177,6 @@ impl Layout {
fn span_in_layout(&self, ident: &Member) -> Option<Span> {
match self {
Layout::Pack(layout, _)
| Layout::Margins(layout, _, _)
| Layout::Frame(_, layout, _)
| Layout::Button(_, layout, _)
| Layout::NonNavigable(layout)
Expand Down
14 changes: 12 additions & 2 deletions crates/kas-widgets/src/adapt/adapt_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
use super::*;
use kas::cast::{Cast, CastFloat};
use kas::dir::Directional;
use kas::dir::{Directional, Directions};
use kas::geom::Vec2;
use kas::layout::{AlignHints, AxisInfo, SizeRules};
use kas::text::AccessString;
use kas::theme::SizeCx;
use kas::theme::{MarginStyle, SizeCx};
#[allow(unused)] use kas::Events;
use kas::Widget;
use std::fmt::Debug;
Expand Down Expand Up @@ -55,6 +55,16 @@ pub trait AdaptWidget: Widget + Sized {
Pack::new(self, hints)
}

/// Specify margins
///
/// This replaces a widget's margins.
///
/// Returns a wrapper around the input widget.
#[must_use]
fn margins(self, dirs: Directions, style: MarginStyle) -> Margins<Self> {
Margins::new(self, dirs, style)
}

/// Map data type via a function
///
/// Returns a wrapper around the input widget.
Expand Down
48 changes: 46 additions & 2 deletions crates/kas-widgets/src/adapt/align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@

//! Alignment
use kas::dir::Directions;
use kas::layout::PackStorage;
use kas::prelude::*;
use kas::theme::MarginStyle;

impl_scope! {
/// Apply an alignment hint
Expand Down Expand Up @@ -36,8 +38,7 @@ impl_scope! {

impl Layout for Self {
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
self.inner
.size_rules(sizer, axis.with_align_hints(self.hints))
self.inner.size_rules(sizer, axis.with_align_hints(self.hints))
}
}
}
Expand Down Expand Up @@ -81,3 +82,46 @@ impl_scope! {
}
}
}

impl_scope! {
/// Specify margins
///
/// This replaces a widget's margins.
///
/// Usually, this type will be constructed through one of the methods on
/// [`AdaptWidget`](crate::adapt::AdaptWidget).
#[autoimpl(Deref, DerefMut using self.inner)]
#[autoimpl(class_traits using self.inner where W: trait)]
#[widget{ derive = self.inner; }]
pub struct Margins<W: Widget> {
pub inner: W,
dirs: Directions,
style: MarginStyle,
}

impl Self {
/// Construct
#[inline]
pub fn new(inner: W, dirs: Directions, style: MarginStyle) -> Self {
Margins { inner, dirs, style }
}
}

impl Layout for Self {
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
let mut child_rules = self.inner.size_rules(sizer.re(), axis);
if self.dirs.intersects(Directions::from(axis)) {
let mut rule_margins = child_rules.margins();
let margins = sizer.margins(self.style).extract(axis);
if self.dirs.intersects(Directions::LEFT | Directions::UP) {
rule_margins.0 = margins.0;
}
if self.dirs.intersects(Directions::RIGHT | Directions::DOWN) {
rule_margins.1 = margins.1;
}
child_rules.set_margins(rule_margins);
}
child_rules
}
}
}
2 changes: 1 addition & 1 deletion crates/kas-widgets/src/adapt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub use adapt::{Adapt, Map};
pub use adapt_cx::{AdaptConfigCx, AdaptEventCx};
pub use adapt_events::AdaptEvents;
pub use adapt_widget::*;
pub use align::{Align, Pack};
pub use align::{Align, Margins, Pack};
#[doc(inline)] pub use kas::hidden::MapAny;
pub use reserve::Reserve;
pub use with_label::WithLabel;
6 changes: 0 additions & 6 deletions tests/layout_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,3 @@ fn aligned_row() {
"three", "four"
],]);
}

#[test]
fn margins() {
use_widget(kas::margins!(1.0 em, "abc"));
use_widget(kas::margins!(vert = none, "abc"));
}

0 comments on commit 2d720e1

Please sign in to comment.