belly
belly copied to clipboard
[wip] collections & list widget
This is introduction to list widgets & collections. It introduces:
- the
Databasesystem param. You can thing of it as of the entity with multiple collections as children. - the
Collectioncomponent. - the
Item<T>component. Entity withCollectioncontains multipleItem<T>entities as children. - the
CollectionRef<T>struct. It has vector-like api: you can push, pop, iter items, etc. - the
<list>widget. The<list>acceptscollection:Entityandrender-item:Fn(Entity) -> Emlcallback.<list>is responsible for reacting on collection changes (adding or removing items), callingrender-itemcallback when item added to collection and keeping track of rendered items, i.e. mapitem-entity -> rendered-entity.
This is currently working example:
pub struct TaskData {
name: String,
complete: bool,
}
impl Task {
pub fn complete_label(&self) -> &'static str {
if self.complete {
"Completed"
} else {
"Complete"
}
}
}
fn setup(mut commands: Commands, mut db: Database<'w, 's, Task>) {
commands.spawn(Camera2dBundle::default());
let todo = db
.add_collection()
.push(Task {
name: "hello".into(),
complete: false,
})
.push(Task {
name: "".into(),
complete: true,
})
.id();
commands.add(eml! {
<body>
<list collection=todo render-item=|item| eml! {
<span c:task>
<textinput
bind:value=from!(item, Item<Task>:name)
bind:value=to!(item, Item<Task>:name)
/>
<button mode="toggle"
bind:pressed=from!(item, Item<Task>:complete)
bind:pressed=to!(item, Item<Task>:complete)
>
{from!(item, Item<Task>:complete_label())}
</button>
</span>
}/>
<button on:press=run!(|ctx| {
ctx.push_item(todo, Task {
name: format!("Yet another task"),
complete: false
});
})>"Add task"</button>
</body>
});
}
Things to be done:
- [ ] Implement missed methods for
CollectionReflikepop(),remove(),swap(), etc. - [ ] change
render-itemsignature - now it accepts only item entity, but should accept both collection and item entities - [ ] Support
SystemParamparameters for event handlers - [ ] Implement named render template tag and use it instead of callback
What is render template tag?
// this is how render-item defines now
eml! {
<list render-item=|item| { ... } />
}
There are several problems with this approach:
render-itempasses as param. There is no compile-time checks, only runtime warnings.- there is no way to translate this part to asset-based eml.
It is required to introduce <render> compile-time tag that act just like callback
eml! {
<list collection=collection_entity>
<render:item task>
<label bind:value=from!(task, Item<Task>:name) />
</render>
</list>
}