Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

on 事件咒符

on EventKind 子句把事件处理器附着到部件上。

on 是保留关键字:已注册为 custom token,所以 on Foo 永不会被误认成名为 on 的部件。

形态 B — body 之后的修饰链

use xrune::ui;
fn save() {}
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
button (text: "Save") {} on Tap {
    save();
}
}
}
fn main() {}

嵌进某个 body 时,形态 B 附着到紧靠前的兄弟部件附着到父部件:

use xrune::ui;
fn save() {}
fn cancel() {}
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
column {
    button (text: "Save") {}
    on Tap { save(); }            /* 附到上面那个 button */

    button (text: "Cancel") {}
    on Tap { cancel(); }          /* 附到 cancel 那个 button */
}
}
}
fn main() {}

同一部件可以串多条形态 B:

use xrune::ui;
fn save() {}
fn hint() {}
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
button (text: "Save") {}
    on Tap { save(); }
    on Hover { hint(); }
}
}
fn main() {}

形态 C — 属性与 body 之间

use xrune::ui;
fn commit() {}
fn lock() {}
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
slider (min: 0, max: 100)
    on ValueChanged(2) { commit(); }
    on DragStart { lock(); }
    {}
}
}
fn main() {}

同一部件可叠多条形态 C。末尾的 {} 可省,不写时部件就是没有子节点:

use xrune::ui;
fn fire() {}
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
view ()
    on Tap { fire(); }
}
}
fn main() {}

形态 B 与形态 C 的处理器都汇入同一个 Vec<DsOn>,由 DsWidget::get_on_handlers() 一次取出。同一个部件上两种形态混用合法。

带体形态 vs 回调形态

事件处理器可以带 body 块:

use xrune::ui;
struct State; impl State { fn toggle(&self) {} }
fn app(parent: i32, state: State) {
ui! {
    :(
        parent: parent
    :)
button () {}
on Tap {
    state.toggle();
}
}
}
fn main() {}

也可以仅带末尾一个回调表达式、不带 body:

use xrune::ui;
fn callback() {}
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
button () {}
on Tap(callback)
on Tap(2, callback)
}
}
fn main() {}

带体形态下 DsOn::get_body() 返回 Some(&syn::Block);回调形态下返回 None,由符文师自行决定 get_args() 末尾那个元素的语义:通常的约定是「事件触发时所调起的表达式」。

子句若既无 body 又无 args,即为 parse 错。

限定的事件名

use xrune::ui;
struct Slider;
fn commit() {}
fn app(parent: i32) {
ui! {
    :(
        parent: parent
    :)
slider () {}
on Slider::ValueChanged { commit(); }
}
}
fn main() {}

get_qualifier() 返回 Some(Slider)get_name() 返回 ValueChanged。限定段只允许一段Foo::Bar::Baz 直接拒收。

参数

on EventKind(…) 圆括号里是逗号分隔的 syn::Expr 列表。符文师由 get_args() 取出。常见形态:

on Tap { … }                        /* args: [], body 在 */
on Tap(2) { … }                     /* args: [2], body 在 */
on Tap(cb)                          /* 回调形态,无 body */
on Tap(2, cb)                       /* count + 回调 */

子句 body 与 args 两者皆无时,即为 parse 错:每个 on 至少要带其中一种。

源码出处

ds_on.rstests.rs 里的 form_b_* / form_c_* 用例。这套形态由 xrune-fmt 的 formatter 来回誊写一遍验过:每次此处形态有改,同一 commit 必带 fmt 更新。