Skip to content

Commit 21c94e7

Browse files
authored
Merge pull request #478 from kas-gui/work3
Remove input data from widget layout syntax items
2 parents a67910c + a773273 commit 21c94e7

File tree

6 files changed

+45
-124
lines changed

6 files changed

+45
-124
lines changed

crates/kas-macros/src/lib.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -208,27 +208,33 @@ pub fn impl_scope(input: TokenStream) -> TokenStream {
208208
/// implementation of `Tile::nav_next`, with a couple of exceptions
209209
/// (where macro-time analysis is insufficient to implement this method).
210210
///
211-
/// > [_Column_], [_Row_], [_List_] [_AlignedColumn_], [_AlignedRow_], [_Grid_], [_Float_], [_Frame_] :\
211+
/// > [_Column_], [_Row_], [_List_] [_AlignedColumn_], [_AlignedRow_], [_Grid_],
212+
/// > [_Float_], [_Frame_] :\
212213
/// >    These stand-alone macros are explicitly supported in this position.\
213-
///
214+
/// >
214215
/// > _Single_ :\
215216
/// >    `self` `.` _Member_\
216-
/// >    A named child: `self.foo` (more precisely, this matches any expression starting `self`, and uses `&mut (#expr)`)
217+
/// >    A named child: `self.foo` (more precisely, this matches any
218+
/// > expression starting `self`, and uses `&mut (#expr)`).
217219
/// >
218220
/// > _WidgetConstructor_ :\
219221
/// >    _Expr_\
220-
/// >    An expression yielding a widget, e.g. `Label::new("Hello world")`. The result must be an object of some type `W: Widget`.
222+
/// >    An expression yielding a widget, e.g.
223+
/// > `Label::new("Hello world")`. The result must be an object of some type
224+
/// > `W: Widget<Data = ()>`. This widget will be stored in a hidden field and
225+
/// > is accessible through `Tile::get_child` but does not receive input data.
221226
/// >
222227
/// > _LabelLit_ :\
223228
/// > &nbsp;&nbsp; _StrLit_\
224-
/// > &nbsp;&nbsp; A string literal generates a label widget, e.g. "Hello world". This is an internal type without text wrapping.
225-
/// >
229+
/// > &nbsp;&nbsp; A string literal generates a label widget, e.g. "Hello
230+
/// > world". This is an internal type without text wrapping.
231+
///
226232
/// Additional syntax rules (not layout items):
227233
///
228234
/// > _Member_ :\
229235
/// > &nbsp;&nbsp; _Ident_ | _Index_\
230236
/// > &nbsp;&nbsp; The name of a struct field or an index into a tuple struct.
231-
/// >
237+
///
232238
/// ## Examples
233239
///
234240
/// A simple example is the

crates/kas-macros/src/make_layout.rs

+26-104
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use proc_macro_error2::emit_error;
1010
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
1111
use syn::parse::{Parse, ParseStream, Result};
1212
use syn::spanned::Spanned;
13-
use syn::{braced, bracketed, parenthesized, parse_quote, token};
14-
use syn::{Expr, Ident, LitStr, Member, Token, Type};
13+
use syn::{braced, bracketed, parenthesized, token};
14+
use syn::{Expr, Ident, LitStr, Member, Token};
1515

1616
#[allow(non_camel_case_types)]
1717
mod kw {
@@ -21,24 +21,12 @@ mod kw {
2121
custom_keyword!(pack);
2222
custom_keyword!(column);
2323
custom_keyword!(row);
24-
custom_keyword!(right);
25-
custom_keyword!(left);
26-
custom_keyword!(down);
27-
custom_keyword!(up);
28-
custom_keyword!(center);
29-
custom_keyword!(stretch);
3024
custom_keyword!(frame);
3125
custom_keyword!(list);
3226
custom_keyword!(grid);
33-
custom_keyword!(default);
34-
custom_keyword!(top);
35-
custom_keyword!(bottom);
3627
custom_keyword!(aligned_column);
3728
custom_keyword!(aligned_row);
3829
custom_keyword!(float);
39-
custom_keyword!(px);
40-
custom_keyword!(em);
41-
custom_keyword!(map_any);
4230
custom_keyword!(with_direction);
4331
custom_keyword!(with_style);
4432
custom_keyword!(with_background);
@@ -48,15 +36,14 @@ mod kw {
4836
pub struct StorageFields {
4937
pub ty_toks: Toks,
5038
pub def_toks: Toks,
51-
pub used_data_ty: bool,
5239
}
5340

5441
#[derive(Debug)]
5542
pub struct Tree(Layout);
5643
impl Tree {
57-
pub fn storage_fields(&self, children: &mut Vec<Child>, data_ty: &Type) -> StorageFields {
44+
pub fn storage_fields(&self, children: &mut Vec<Child>) -> StorageFields {
5845
let mut fields = StorageFields::default();
59-
self.0.append_fields(&mut fields, children, data_ty);
46+
self.0.append_fields(&mut fields, children);
6047
fields
6148
}
6249

@@ -138,7 +125,6 @@ enum Layout {
138125
Float(LayoutList<()>),
139126
Grid(Ident, GridDimensions, LayoutList<CellInfo>),
140127
Label(Ident, LitStr),
141-
MapAny(Box<Layout>, MapAny),
142128
}
143129

144130
#[derive(Debug)]
@@ -148,6 +134,7 @@ struct ExprMember {
148134
member: Member,
149135
}
150136

137+
#[allow(unused)]
151138
#[derive(Debug)]
152139
enum Direction {
153140
Left,
@@ -192,20 +179,17 @@ impl Layout {
192179

193180
loop {
194181
if let Ok(dot_token) = input.parse::<Token![.]>() {
195-
if input.peek(kw::map_any) {
196-
let map_any = MapAny::parse(dot_token, input)?;
197-
layout = Layout::MapAny(Box::new(layout), map_any);
198-
} else if input.peek(kw::align) {
182+
if input.peek(kw::align) {
199183
let align = Align::parse(dot_token, input)?;
200184
layout = Layout::Align(Box::new(layout), align);
201185
} else if input.peek(kw::pack) {
202186
let pack = Pack::parse(dot_token, input, core_gen)?;
203187
layout = Layout::Pack(Box::new(layout), pack);
204188
} else if let Ok(ident) = input.parse::<Ident>() {
205189
let note_msg = if matches!(&layout, &Layout::Frame(_, _, _, _)) {
206-
"supported methods on layout objects: `map_any`, `align`, `pack`, `with_style`, `with_background`"
190+
"supported methods on layout objects: `align`, `pack`, `with_style`, `with_background`"
207191
} else {
208-
"supported methods on layout objects: `map_any`, `align`, `pack`"
192+
"supported methods on layout objects: `align`, `pack`"
209193
};
210194
emit_error!(
211195
ident, "method not supported here";
@@ -484,24 +468,7 @@ impl ToTokens for ExprMember {
484468

485469
impl Parse for Direction {
486470
fn parse(input: ParseStream) -> Result<Self> {
487-
let lookahead = input.lookahead1();
488-
if lookahead.peek(kw::right) {
489-
let _: kw::right = input.parse()?;
490-
Ok(Direction::Right)
491-
} else if lookahead.peek(kw::down) {
492-
let _: kw::down = input.parse()?;
493-
Ok(Direction::Down)
494-
} else if lookahead.peek(kw::left) {
495-
let _: kw::left = input.parse()?;
496-
Ok(Direction::Left)
497-
} else if lookahead.peek(kw::up) {
498-
let _: kw::up = input.parse()?;
499-
Ok(Direction::Up)
500-
} else if lookahead.peek(Token![self]) {
501-
Ok(Direction::Expr(input.parse()?))
502-
} else {
503-
Err(lookahead.error())
504-
}
471+
Ok(Direction::Expr(input.parse()?))
505472
}
506473
}
507474

@@ -524,24 +491,6 @@ impl ToTokens for Direction {
524491
}
525492
}
526493

527-
#[derive(Debug)]
528-
#[allow(unused)]
529-
struct MapAny {
530-
pub dot_token: Token![.],
531-
pub kw: kw::map_any,
532-
pub paren_token: token::Paren,
533-
}
534-
impl MapAny {
535-
fn parse(dot_token: Token![.], input: ParseStream) -> Result<Self> {
536-
let _content;
537-
Ok(MapAny {
538-
dot_token,
539-
kw: input.parse()?,
540-
paren_token: parenthesized!(_content in input),
541-
})
542-
}
543-
}
544-
545494
#[derive(Debug)]
546495
#[allow(unused)]
547496
struct Align {
@@ -612,10 +561,10 @@ impl Pack {
612561
}
613562

614563
impl Layout {
615-
fn append_fields(&self, fields: &mut StorageFields, children: &mut Vec<Child>, data_ty: &Type) {
564+
fn append_fields(&self, fields: &mut StorageFields, children: &mut Vec<Child>) {
616565
match self {
617566
Layout::Align(layout, _) => {
618-
layout.append_fields(fields, children, data_ty);
567+
layout.append_fields(fields, children);
619568
}
620569
Layout::Single(_) => (),
621570
Layout::Pack(layout, pack) => {
@@ -626,18 +575,17 @@ impl Layout {
626575
fields
627576
.def_toks
628577
.append_all(quote! { #stor: Default::default(), });
629-
layout.append_fields(fields, children, data_ty);
578+
layout.append_fields(fields, children);
630579
}
631580
Layout::Widget(ident, expr) => {
632581
children.push(Child::new_core(ident.clone().into()));
633582
fields
634583
.ty_toks
635-
.append_all(quote! { #ident: Box<dyn ::kas::Widget<Data = #data_ty>>, });
584+
.append_all(quote! { #ident: Box<dyn ::kas::Widget<Data = ()>>, });
636585
let span = expr.span();
637586
fields
638587
.def_toks
639588
.append_all(quote_spanned! {span=> #ident: Box::new(#expr), });
640-
fields.used_data_ty = true;
641589
}
642590
Layout::Frame(stor, layout, _, _) => {
643591
fields
@@ -646,7 +594,7 @@ impl Layout {
646594
fields
647595
.def_toks
648596
.append_all(quote! { #stor: Default::default(), });
649-
layout.append_fields(fields, children, data_ty);
597+
layout.append_fields(fields, children);
650598
}
651599
Layout::List(stor, _, LayoutList(list)) => {
652600
fields
@@ -660,12 +608,12 @@ impl Layout {
660608
quote! { #stor: ::kas::layout::FixedRowStorage<#len>, }
661609
});
662610
for item in list {
663-
item.layout.append_fields(fields, children, data_ty);
611+
item.layout.append_fields(fields, children);
664612
}
665613
}
666614
Layout::Float(LayoutList(list)) => {
667615
for item in list {
668-
item.layout.append_fields(fields, children, data_ty);
616+
item.layout.append_fields(fields, children);
669617
}
670618
}
671619
Layout::Grid(stor, dim, LayoutList(list)) => {
@@ -678,42 +626,18 @@ impl Layout {
678626
.append_all(quote! { #stor: Default::default(), });
679627

680628
for item in list {
681-
item.layout.append_fields(fields, children, data_ty);
629+
item.layout.append_fields(fields, children);
682630
}
683631
}
684632
Layout::Label(ident, text) => {
685633
children.push(Child::new_core(ident.clone().into()));
686634
let span = text.span();
687-
if *data_ty == syn::parse_quote! { () } {
688-
fields
689-
.ty_toks
690-
.append_all(quote! { #ident: ::kas::hidden::StrLabel, });
691-
fields.def_toks.append_all(
692-
quote_spanned! {span=> #ident: ::kas::hidden::StrLabel::new(#text), },
693-
);
694-
} else {
695-
fields.ty_toks.append_all(
696-
quote! { #ident: ::kas::hidden::MapAny<#data_ty, ::kas::hidden::StrLabel>, },
697-
);
698-
fields.def_toks.append_all(
699-
quote_spanned! {span=> #ident: ::kas::hidden::MapAny::new(::kas::hidden::StrLabel::new(#text)), },
700-
);
701-
fields.used_data_ty = true;
702-
}
703-
}
704-
Layout::MapAny(layout, map_any) => {
705-
let start = children.len();
706-
layout.append_fields(fields, children, &parse_quote! { () });
707-
let map_expr: Expr = parse_quote! { &() };
708-
for child in &mut children[start..] {
709-
if let Some(ref expr) = child.data_binding {
710-
if *expr != map_expr {
711-
emit_error!(map_any.kw, "invalid data type mapping")
712-
}
713-
} else {
714-
child.data_binding = Some(map_expr.clone());
715-
}
716-
}
635+
fields
636+
.ty_toks
637+
.append_all(quote! { #ident: ::kas::hidden::StrLabel, });
638+
fields.def_toks.append_all(
639+
quote_spanned! {span=> #ident: ::kas::hidden::StrLabel::new(#text), },
640+
);
717641
}
718642
}
719643
}
@@ -764,7 +688,6 @@ impl Layout {
764688
Layout::Label(stor, _) => {
765689
quote! { layout::Visitor::single(&mut #core_path.#stor) }
766690
}
767-
Layout::MapAny(layout, _) => return layout.generate(core_path),
768691
})
769692
}
770693

@@ -777,10 +700,9 @@ impl Layout {
777700
output: &mut Vec<usize>,
778701
) -> std::result::Result<(), (Span, &'static str)> {
779702
match self {
780-
Layout::Align(layout, _)
781-
| Layout::Pack(layout, _)
782-
| Layout::Frame(_, layout, _, _)
783-
| Layout::MapAny(layout, _) => layout.nav_next(children, output),
703+
Layout::Align(layout, _) | Layout::Pack(layout, _) | Layout::Frame(_, layout, _, _) => {
704+
layout.nav_next(children, output)
705+
}
784706
Layout::Single(m) => {
785707
for (i, child) in children.enumerate() {
786708
if let ChildIdent::Field(ref ident) = child.ident {

crates/kas-macros/src/widget.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul
184184

185185
let mut stor_defs = Default::default();
186186
if let Some(Layout { ref tree, .. }) = args.layout {
187-
stor_defs = tree.storage_fields(&mut children, &data_ty);
187+
stor_defs = tree.storage_fields(&mut children);
188188
}
189189
if !stor_defs.ty_toks.is_empty() {
190190
let name = format!("_{name}CoreTy");
@@ -796,11 +796,6 @@ pub fn impl_widget(
796796
ChildIdent::Field(ident) => quote! { self.#ident },
797797
ChildIdent::CoreField(ident) => quote! { #core_path.#ident },
798798
};
799-
// TODO: incorrect or unconstrained data type of child causes a poor error
800-
// message here. Add a constaint like this (assuming no mapping fn):
801-
// <#ty as WidgetNode::Data> == Self::Data
802-
// But this is unsupported: rust#20041
803-
// predicates.push(..);
804799

805800
get_mut_rules.append_all(if let Some(ref data) = child.data_binding {
806801
quote! { #i => closure(#path.as_node(#data)), }

crates/kas-macros/src/widget_args.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl Child {
238238
Child {
239239
ident: ChildIdent::CoreField(ident),
240240
attr_span: None,
241-
data_binding: None,
241+
data_binding: Some(syn::parse_quote! { &() }),
242242
}
243243
}
244244
}

crates/kas-widgets/src/combobox.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl_scope! {
2929
/// when selected. If a handler is specified via [`Self::with`] or
3030
/// [`Self::with_msg`] then this message is passed to the handler and not emitted.
3131
#[widget {
32-
layout = frame!(row! [self.label, self.mark])
32+
layout = frame!(row! [self.label, Mark::new(MarkStyle::Point(Direction::Down))])
3333
.with_style(FrameStyle::Button)
3434
.align(AlignHints::CENTER);
3535
navigable = true;
@@ -40,8 +40,6 @@ impl_scope! {
4040
#[widget(&())]
4141
label: Label<String>,
4242
#[widget(&())]
43-
mark: Mark,
44-
#[widget(&())]
4543
popup: Popup<AdaptEvents<Column<Vec<MenuEntry<V>>>>>,
4644
active: usize,
4745
opening: bool,
@@ -233,7 +231,6 @@ impl<A, V: Clone + Debug + Eq + 'static> ComboBox<A, V> {
233231
ComboBox {
234232
core: Default::default(),
235233
label,
236-
mark: Mark::new(MarkStyle::Point(Direction::Down)),
237234
popup: Popup::new(
238235
AdaptEvents::new(Column::new(entries)).on_messages(|cx, _, _| {
239236
if let Some(_) = cx.try_peek::<V>() {

examples/gallery.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,13 @@ fn widgets() -> Box<dyn Widget<Data = AppData>> {
107107
let popup_edit_box = impl_anon! {
108108
#[widget{
109109
layout = row! [
110-
format_data!(data: &Data, "{}", &data.text),
111-
Button::label_msg("&Edit", MsgEdit).map_any(),
110+
self.text,
111+
Button::label_msg("&Edit", MsgEdit),
112112
];
113113
}]
114114
struct {
115115
core: widget_core!(),
116+
#[widget] text: Text<Data, String> = format_data!(data: &Data, "{}", &data.text),
116117
#[widget(&())] popup: Popup<TextEdit> = Popup::new(TextEdit::new("", true), Direction::Down),
117118
}
118119
impl Events for Self {

0 commit comments

Comments
 (0)