Small, and disjoint from #12 — this touches `task.rs`, `harness.rs` and `render_state.rs`, none of which #12 goes near. `Tasks` held an `Arc<Window>` only to call `request_redraw` when a task finished, which made the task queue, and so `DefaultRsc`, impossible to build without a window. It now takes an `Arc<dyn WakeTaskQueue>`, and `Window` implements it. Waking also moves from *the task ended* to *an update was sent*, which is when there is actually something for the host to apply. A task that keeps running after sending one no longer holds it until it finishes, and a task that sends none no longer asks for a frame nothing needs. `iris::harness` is what that buys. `UiRenderState` already does layout, hit testing and primitive building with no surface, so a test can build a tree, run frames, move a pointer and read back where widgets landed. `tests/harness.rs` covers span layout, resize relayout, press routing, hover start and end, wheel scrolling with its clamp, and a task update reaching the tree. None of them could be written before, since the only way into layout was a window. It does not draw. A claim about pixels still needs a real surface — I checked this one against the rig rather than asserting it: `examples/task` under headless sway, centre pixel `ff0000` before the click and `0000ff` after, so the windowed path still applies task updates under the new wake. The only core change is `UiRenderState::output_size()`, so that a host reading back the size it set does not have to keep a second copy. --------- Co-authored-by: iris <2+iris@noreply.localhost> Reviewed-on: iris/iris#15 Reviewed-by: iris <2+iris@noreply.localhost> Co-authored-by: AIris <4+iris-ai@noreply.localhost>
50 lines
1.0 KiB
Rust
50 lines
1.0 KiB
Rust
use iris::prelude::*;
|
|
|
|
fn main() {
|
|
DefaultApp::<State>::run();
|
|
}
|
|
|
|
#[derive(DefaultUiState)]
|
|
struct State {
|
|
ui_state: DefaultUiState,
|
|
}
|
|
|
|
type Rsc = DefaultRsc<State>;
|
|
|
|
#[derive(Clone, Copy, WidgetView)]
|
|
struct Test {
|
|
#[root]
|
|
root: WeakWidget<Rect>,
|
|
cur: WeakState<bool>,
|
|
}
|
|
|
|
impl Test {
|
|
pub fn new(rsc: &mut Rsc) -> Self {
|
|
let root = rect(Color::RED).add(rsc);
|
|
let cur = rsc.create_state(root, false);
|
|
Self { root, cur }
|
|
}
|
|
pub fn toggle(&self, rsc: &mut Rsc) {
|
|
let cur = &mut rsc[self.cur];
|
|
*cur = !*cur;
|
|
if *cur {
|
|
rsc[self.root].color = Color::BLUE;
|
|
} else {
|
|
rsc[self.root].color = Color::RED;
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DefaultAppState for State {
|
|
fn new(mut ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>, _: Proxy<Self>) -> Self {
|
|
let test = Test::new(rsc);
|
|
|
|
test.on(CursorSense::click(), move |_, rsc| {
|
|
test.toggle(rsc);
|
|
})
|
|
.set_root(rsc, &mut ui_state);
|
|
|
|
Self { ui_state }
|
|
}
|
|
}
|