You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the previous example, our top-level `AppData` was `()`: `.build(())`.
71
-
72
-
This time, we want to store our counter in top-level `AppData`. But, as we saw with `Adapt`, state which doesn't react to messages is useless; hence we use a custom type and implement a message handler:
70
+
In the previous example, our top-level `AppData` was `()` and our mutable state was stored in an [`Adapt`] widget. This time, we will store our counter in top-level `AppData`, in a custom type which includes a message handler:
73
71
```rust
74
72
# externcrate kas;
75
73
# usekas::{messages::MessageStack, Action};
@@ -90,13 +88,9 @@ impl kas::app::AppData for Count {
90
88
}
91
89
}
92
90
```
93
-
[`AppData::handle_messages`] is less succinct than [`Adapt::on_message`], but dones the same job. The method notifies when widgets must be updated by returning [`Action::UPDATE`].
94
-
95
-
### As an input
96
-
97
-
We initialise our app with an instance of `Count`: `.build(Count(0))`.
91
+
[`AppData::handle_messages`] is more verbose than [`Adapt::on_message`], but does the same job. The method notifies when widgets must be updated by returning [`Action::UPDATE`].
98
92
99
-
Note that `Count`is now an input to the widgets we construct:
93
+
To integrate this into our example, we pass a `Count`object into [`kas::runner::Builder::build`] and adjust the prototype of `counter` to:
100
94
```rust
101
95
# externcrate kas;
102
96
# usekas::{messages::MessageStack, Action};
@@ -125,7 +119,7 @@ let initial: Data = (Count(0), 1);
125
119
```
126
120
Note that our local data includes a *copy* of the top-level data `Count` (along with an initial value, `Count(0)`, which will be replaced before it is ever used).
127
121
128
-
We'll skip right over the widget declarations to the new `Adapt` node:
122
+
We'll skip right over the widget declarations to the new [`Adapt`] node:
129
123
```rust
130
124
# externcrate kas;
131
125
# usekas::widgets::{label_any, Adapt};
@@ -136,18 +130,21 @@ We'll skip right over the widget declarations to the new `Adapt` node:
136
130
# structSetValue(i32);
137
131
# letui=label_any("");
138
132
# letinitial= (Count(0), 1);
139
-
Adapt::new(ui, initial)
140
-
.on_update(|_, state, count|state.0=*count)
141
-
.on_message(|_, state, SetValue(v)|state.1=v)
133
+
letui=ui
134
+
.with_state(initial)
135
+
.on_update(|_, state, count|state.0=*count)
136
+
.on_message(|_, state, SetValue(v)|state.1=v);
142
137
# }
143
138
```
144
139
The notable addition here is [`Adapt::on_update`], which takes a closure over the expected mutable reference to local `state` as well as *input* data `count` (i.e. the top-level data), allowing us to update local state with the latest top-level `count`.
145
140
146
-
Aside: this is really not how *adapting* top-level data with local state is *supposed* to work. Ideally, we'd omit the local copy of `Count` entirely and pass something like `(&Count, i32)` to local widgets. But, as any Rustacean knows, a reference requires a lifetime, and dealing with lifetimes can get complicated. The plan is to update our approach once Rust supports object-safe GATs (also known as Extended Generic Associated Types).
141
+
Aside: you may wonder why we store `count` in [`Adapt`]'s state at all. Why not simply pass `(&Count, &i32)` (count, increment) down to the local UI? The answer is that we can't, because of lifetimes. To be specific, the input data type is formalized as an associated type, [`Widget::Data`], which must outlive instances of that type: that is any references embedded in an input data type must outlive the instances of the widgets they are passed to. Moreover, [`AppData`] requires lifetime `'static` (more as a simplification than because we truely couldn't support non-static lifetimes here, though there really isn't much use for them).
142
+
143
+
Aside aside: could we not make [`Widget::Data`] into a Generic Associated Type (GAT) to support lifetimes shorter than that of the widget object? Well, yes, but traits with GATs are not (yet) object-safe. This is a problem because object-safe widget types are important (both for variadic layout — e.g. a `TabStack` where pages use different widget types — and more fundamentally, namely to make [`Node`] work). So *maybe* this will be possible eventually, dependent on future Rust development.
147
144
148
-
## Multiple windows
145
+
## Running multiple windows
149
146
150
-
It barely seems worth mentioning, but there's nothing stopping us from calling `fn counter`multiple times and constructing a new window around each:
147
+
Constructing multiple windows under a UI runner is simple:
0 commit comments