jkb0o / belly

Define the Bevy UI tree with `eml!`, style it using a very-css-like `ess` syntax and relate data data with `bind!` and `connect!`
Apache License 2.0
394 stars 33 forks source link

[eml] Widget prop change handlers & expressions #69

Closed jkb0o closed 1 year ago

jkb0o commented 1 year ago

The problem

For now you are required to define change event for each property by hand, like it is done for <btngroup>:

#[param(value: String => BtnGroup:value)]
#[signal(value_change: ValueChanged<String> => value_changed)]
fn buttongroup(ctx: &mut WidgetContext) { ... }

You can connect to the value_change event later:

let label = commands.spawn_empty().id();
commands.add(eml! {
  <body>
    <label {label}/>
    <btngroup on:value_change=run!(for label |ctx, label:Label| {
       label.value = format!(
         "value changed from {} to {}",
         ctx.old_value(),
         ctx.new_value()
    })/>
  </body>
})

There are several problems with such approach:

The solution

When the entity associations (#68) and default widget component (#todo) will be done, it is easy to implement change handler expression syntax:

#[prop(value: String)
fn buttongroup() { eml! { ... } }
commands.add(eml! {
  <body>
    <entity {label as Label}/>
    <label:label/>
    <btngroup value:changed={|change, label| label.value=format!(
      "value changed from {} to {}", change.from(), change.to()
    )}/>
</body>

Change registrators could be done for each widget's #[prop(...)] automatically. ChangeHandlerExpression parser should detect built-in (without type-spec), custom WorldQuery and SystemParam arguments:

There is no ctx argument support as far as we do not need context anymore when fetching SystemParam in handlers is done.

Cahnge detection could be easaly done inside the bind systems (e.g. generate Change<T> event when value cahnged.

jkb0o commented 1 year ago

This will be done right in polako (#77)