iris: fold render state into Ui
This commit is contained in:
1 parent
44a5da378b
commit
9b4c690916
25 files changed
+421
-390
No files matched your search
+3
-9
@@ -3,9 +3,7 @@ use crate::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn a_named_widget_reaches_the_tree_with_its_role_and_bounds() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let leaf: WeakWidget<Rect> = rect(PaintId::WHITE).label("Add task").add(&mut rsc);
|
||||
let root = leaf.upgrade(&mut rsc).any();
|
||||
let mut render = UiRenderState::new();
|
||||
@@ -37,9 +35,7 @@ fn a_named_widget_reaches_the_tree_with_its_role_and_bounds() {
|
||||
|
||||
#[test]
|
||||
fn a_widget_with_no_label_never_reaches_the_tree() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let root = rsc.ui.widgets.add_strong(rect(PaintId::WHITE));
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((800.0, 600.0));
|
||||
@@ -55,9 +51,7 @@ fn a_widget_with_no_label_never_reaches_the_tree() {
|
||||
|
||||
#[test]
|
||||
fn bounds_follow_a_moved_widget_and_updates_stay_incremental() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let leaf: WeakWidget<Rect> = rect(PaintId::WHITE).label("thing").add(&mut rsc);
|
||||
let leaf_strong = leaf.upgrade(&mut rsc).any();
|
||||
let offset = rsc.ui.widgets.add_strong(Offset {
|
||||
|
||||
@@ -4,7 +4,7 @@ use android_view::{
|
||||
jni::{JavaVM, objects::GlobalRef},
|
||||
ndk::native_window::NativeWindow,
|
||||
};
|
||||
use iris_core::{FrameParts, LinearRgba, UiData, UiRenderNode, UiRenderState};
|
||||
use iris_core::{FrameParts, LinearRgba, Ui, UiRenderNode};
|
||||
use pollster::FutureExt;
|
||||
use std::time::Instant;
|
||||
use wgpu::{
|
||||
@@ -330,10 +330,10 @@ impl AndroidRenderer {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ui: &mut UiData, render: &mut UiRenderState) -> FrameDiagnostics {
|
||||
pub fn update(&mut self, ui: &mut Ui) -> FrameDiagnostics {
|
||||
let atlas_pages_grown_prev = self.ui.take_atlas_pages_grown();
|
||||
let image_bind_group_creates_prev = self.ui.take_image_bind_group_creates();
|
||||
let stats = self.ui.update(&self.device, &self.queue, ui, render);
|
||||
let stats = self.ui.update(&self.device, &self.queue, ui);
|
||||
self.frame_count += 1;
|
||||
FrameDiagnostics {
|
||||
masks_resized: stats.masks_resized,
|
||||
|
||||
+46
-27
@@ -123,7 +123,7 @@ pub trait HasAndroidUiState: Sized + 'static {
|
||||
pub trait AndroidAppState: HasAndroidUiState {
|
||||
fn new(ui_state: AndroidUiState, rsc: &mut AndroidRsc<Self>) -> Self;
|
||||
#[allow(unused_variables)]
|
||||
fn back_pressed(&mut self, rsc: &mut AndroidRsc<Self>, render: &mut UiRenderState) -> bool {
|
||||
fn back_pressed(&mut self, rsc: &mut AndroidRsc<Self>) -> bool {
|
||||
false
|
||||
}
|
||||
#[allow(unused_variables)]
|
||||
@@ -167,7 +167,7 @@ impl WindowInsets {
|
||||
}
|
||||
|
||||
pub struct AndroidRsc<State: 'static> {
|
||||
pub ui: UiData,
|
||||
pub ui: Ui,
|
||||
pub events: EventManager<Self>,
|
||||
pub tasks: Tasks<Self>,
|
||||
pub state: WidgetState,
|
||||
@@ -181,10 +181,10 @@ impl<State> AndroidRsc<State> {
|
||||
}
|
||||
|
||||
impl<State> UiRsc for AndroidRsc<State> {
|
||||
fn ui(&self) -> &UiData {
|
||||
fn ui(&self) -> &Ui {
|
||||
&self.ui
|
||||
}
|
||||
fn ui_mut(&mut self) -> &mut UiData {
|
||||
fn ui_mut(&mut self) -> &mut Ui {
|
||||
&mut self.ui
|
||||
}
|
||||
fn on_draw(&mut self, active: &ActiveData) {
|
||||
@@ -232,7 +232,6 @@ impl<State: 'static> HasWidgetState for AndroidRsc<State> {
|
||||
/// Java the same way android-view's own demo does.
|
||||
pub struct IrisViewPeer<State: AndroidAppState> {
|
||||
pub(super) rsc: AndroidRsc<State>,
|
||||
pub(super) render: UiRenderState,
|
||||
pub(super) state: State,
|
||||
task_recv: TaskMsgReceiver<AndroidRsc<State>>,
|
||||
/// The one ruler this view dates everything on: touch samples in
|
||||
@@ -277,7 +276,9 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
|
||||
let ui_state = self.state.android_state_mut();
|
||||
let cursor = ui_state.cursor.clone();
|
||||
let old_focus = ui_state.focus;
|
||||
self.render
|
||||
let render_state = self.rsc.ui.render_state();
|
||||
render_state
|
||||
.get()
|
||||
.run_sensors(&mut self.rsc, &mut self.state, cursor, window_size);
|
||||
|
||||
let ui_state = self.state.android_state_mut();
|
||||
@@ -306,7 +307,11 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
|
||||
|
||||
let ui_state = self.state.android_state_mut();
|
||||
ui_state.cursor.end_frame();
|
||||
if self.render.needs_redraw(&ui_state.root, self.rsc.widgets()) {
|
||||
let render_state = self.rsc.ui.render_state();
|
||||
if render_state
|
||||
.get()
|
||||
.needs_redraw(&ui_state.root, self.rsc.widgets())
|
||||
{
|
||||
ctx.view.post_frame_callback(&mut ctx.env);
|
||||
}
|
||||
}
|
||||
@@ -360,11 +365,17 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
|
||||
"render(): root={:?} widgets={} active={} root_px={:?} out_size={:?}",
|
||||
ui_state.root.is_some(),
|
||||
self.rsc.widgets().len(),
|
||||
self.render.active_widgets(),
|
||||
self.rsc.ui.render_state().get().active_widgets(),
|
||||
ui_state
|
||||
.root
|
||||
.as_ref()
|
||||
.and_then(|r| self.render.window_region(r, &self.rsc)),
|
||||
.and_then(|r| {
|
||||
self.rsc
|
||||
.ui
|
||||
.render_state()
|
||||
.get()
|
||||
.window_region(r, &self.rsc)
|
||||
}),
|
||||
self.window_size(),
|
||||
);
|
||||
}
|
||||
@@ -374,12 +385,12 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
|
||||
ctx.view.post_frame_callback(&mut ctx.env);
|
||||
}
|
||||
let ui_state = self.state.android_state_mut();
|
||||
self.render.update(&ui_state.root, &mut self.rsc);
|
||||
self.rsc.draw(&ui_state.root);
|
||||
let ui_state = self.state.android_state_mut();
|
||||
let Some(renderer) = &mut ui_state.renderer else {
|
||||
return;
|
||||
};
|
||||
let frame_diagnostics = renderer.update(&mut self.rsc.ui, &mut self.render);
|
||||
let frame_diagnostics = renderer.update(&mut self.rsc.ui);
|
||||
if renderer.frame_count() <= DIAGNOSTIC_FRAMES {
|
||||
log::info!(
|
||||
"iris frame diagnostics: frame={} masks_resized={} moves_resized={} \
|
||||
@@ -400,26 +411,33 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
|
||||
.android_state_mut()
|
||||
.frame_report
|
||||
.record(now, parts, animating);
|
||||
crate::diagnostics::log_frame(&self.render, now, parts, animating);
|
||||
let render_state = self.rsc.ui.render_state();
|
||||
crate::diagnostics::log_frame(&render_state.get(), now, parts, animating);
|
||||
if crate::diagnostics::trace_enabled() {
|
||||
let ui_state = self.state.android_state();
|
||||
log::debug!(
|
||||
target: "iris::frame",
|
||||
"render(): after update active={} root_px={:?}",
|
||||
self.render.active_widgets(),
|
||||
self.rsc.ui.render_state().get().active_widgets(),
|
||||
ui_state
|
||||
.root
|
||||
.as_ref()
|
||||
.and_then(|r| self.render.window_region(r, &self.rsc)),
|
||||
.and_then(|r| {
|
||||
self.rsc
|
||||
.ui
|
||||
.render_state()
|
||||
.get()
|
||||
.window_region(r, &self.rsc)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let ui_state = self.state.android_state_mut();
|
||||
if let Some(tree_update) =
|
||||
ui_state
|
||||
.access
|
||||
.update(self.rsc.widgets(), &self.render, &self.rsc)
|
||||
{
|
||||
if let Some(tree_update) = ui_state.access.update(
|
||||
self.rsc.widgets(),
|
||||
&self.rsc.ui.render_state().get(),
|
||||
&self.rsc,
|
||||
) {
|
||||
let ui_state = self.state.android_state_mut();
|
||||
if let Some(events) = ui_state.access_adapter.update_if_active(|| tree_update) {
|
||||
ctx.push_dynamic_deferred_callback(move |env, view| {
|
||||
@@ -467,7 +485,7 @@ impl<State: AndroidAppState> ViewPeer for IrisViewPeer<State> {
|
||||
self.after_input(ctx);
|
||||
return true;
|
||||
}
|
||||
let handled = self.state.back_pressed(&mut self.rsc, &mut self.render);
|
||||
let handled = self.state.back_pressed(&mut self.rsc);
|
||||
if handled {
|
||||
self.after_input(ctx);
|
||||
}
|
||||
@@ -646,7 +664,7 @@ impl<State: AndroidAppState> ViewPeer for IrisViewPeer<State> {
|
||||
// dividing the whole window into a separate logical space, which
|
||||
// is what used to make every `abs`-unit size (a fixed `.height(56)`
|
||||
// in particular) mean something different from a `rest`-based one.
|
||||
self.render.resize((width as f32, height as f32));
|
||||
self.rsc.ui.resize((width as f32, height as f32));
|
||||
|
||||
// `AndroidRenderer::resize` only reconfigures the wgpu surface and
|
||||
// rewrites the window uniform -- device, atlas, buffers and bind
|
||||
@@ -779,9 +797,11 @@ impl<State: AndroidAppState> AccessibilityNodeProvider for IrisViewPeer<State> {
|
||||
ctx: &mut CallbackCtx<'local>,
|
||||
virtual_view_id: jint,
|
||||
) -> AccessibilityNodeInfo<'local> {
|
||||
let render_handle = self.rsc.ui.render_state();
|
||||
let render_state = render_handle.get();
|
||||
let mut source = AndroidAccessSource {
|
||||
widgets: self.rsc.widgets(),
|
||||
render: &self.render,
|
||||
render: &render_state,
|
||||
rsc: &self.rsc,
|
||||
};
|
||||
let ui_state = self.state.android_state_mut();
|
||||
@@ -798,9 +818,11 @@ impl<State: AndroidAppState> AccessibilityNodeProvider for IrisViewPeer<State> {
|
||||
ctx: &mut CallbackCtx<'local>,
|
||||
focus_type: jint,
|
||||
) -> AccessibilityNodeInfo<'local> {
|
||||
let render_handle = self.rsc.ui.render_state();
|
||||
let render_state = render_handle.get();
|
||||
let mut source = AndroidAccessSource {
|
||||
widgets: self.rsc.widgets(),
|
||||
render: &self.render,
|
||||
render: &render_state,
|
||||
rsc: &self.rsc,
|
||||
};
|
||||
let ui_state = self.state.android_state_mut();
|
||||
@@ -869,18 +891,15 @@ pub fn new_peer<'local, State: AndroidAppState>(
|
||||
state: Default::default(),
|
||||
_state: PhantomData,
|
||||
};
|
||||
rsc.ui.text.density = content_scale;
|
||||
rsc.ui.set_density(content_scale);
|
||||
let shared = Rc::new(RefCell::new(Shared::default()));
|
||||
let ui_state = AndroidUiState::new(shared.clone(), content_scale);
|
||||
let mut state = State::new(ui_state, &mut rsc);
|
||||
let platform_vm = env.get_java_vm().unwrap();
|
||||
let platform_view = env.new_global_ref(&view.0).unwrap();
|
||||
state.platform_ready(&mut rsc, platform_vm, platform_view);
|
||||
let mut render = UiRenderState::new();
|
||||
render.set_density(content_scale);
|
||||
let peer = IrisViewPeer {
|
||||
rsc,
|
||||
render,
|
||||
state,
|
||||
task_recv,
|
||||
device_clock: None,
|
||||
|
||||
+33
-37
@@ -99,30 +99,18 @@ pub trait DefaultAppState: HasDefaultUiState {
|
||||
fn new(ui_state: DefaultUiState, rsc: &mut DefaultRsc<Self>, proxy: Proxy<Self::Event>)
|
||||
-> Self;
|
||||
#[allow(unused_variables)]
|
||||
fn event(
|
||||
&mut self,
|
||||
event: Self::Event,
|
||||
rsc: &mut DefaultRsc<Self>,
|
||||
render: &mut UiRenderState,
|
||||
) {
|
||||
}
|
||||
fn event(&mut self, event: Self::Event, rsc: &mut DefaultRsc<Self>) {}
|
||||
#[allow(unused_variables)]
|
||||
fn exit(&mut self, rsc: &mut DefaultRsc<Self>, render: &mut UiRenderState) {}
|
||||
fn exit(&mut self, rsc: &mut DefaultRsc<Self>) {}
|
||||
#[allow(unused_variables)]
|
||||
fn window_event(
|
||||
&mut self,
|
||||
event: WindowEvent,
|
||||
rsc: &mut DefaultRsc<Self>,
|
||||
render: &mut UiRenderState,
|
||||
) {
|
||||
}
|
||||
fn window_event(&mut self, event: WindowEvent, rsc: &mut DefaultRsc<Self>) {}
|
||||
fn window_attributes() -> WindowAttributes {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultRsc<State: 'static> {
|
||||
pub ui: UiData,
|
||||
pub ui: Ui,
|
||||
pub events: EventManager<Self>,
|
||||
pub tasks: Tasks<Self>,
|
||||
pub state: WidgetState,
|
||||
@@ -150,11 +138,11 @@ impl<State> DefaultRsc<State> {
|
||||
}
|
||||
|
||||
impl<State> UiRsc for DefaultRsc<State> {
|
||||
fn ui(&self) -> &UiData {
|
||||
fn ui(&self) -> &Ui {
|
||||
&self.ui
|
||||
}
|
||||
|
||||
fn ui_mut(&mut self) -> &mut UiData {
|
||||
fn ui_mut(&mut self) -> &mut Ui {
|
||||
&mut self.ui
|
||||
}
|
||||
|
||||
@@ -204,7 +192,6 @@ impl<State: 'static> HasWidgetState for DefaultRsc<State> {
|
||||
|
||||
pub struct DefaultApp<State: DefaultAppState> {
|
||||
rsc: DefaultRsc<State>,
|
||||
render: UiRenderState,
|
||||
state: State,
|
||||
task_recv: TaskMsgReceiver<DefaultRsc<State>>,
|
||||
}
|
||||
@@ -232,26 +219,22 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
// `content_scale`. See `iris_core::TextData::density` for why the
|
||||
// shaper keeps its own.
|
||||
let scale = content_scale(default_state.window.as_ref());
|
||||
rsc.ui.text.density = scale;
|
||||
rsc.ui.set_density(scale);
|
||||
let state = State::new(default_state, &mut rsc, proxy);
|
||||
let mut render = UiRenderState::new();
|
||||
render.set_density(scale);
|
||||
Self {
|
||||
rsc,
|
||||
state,
|
||||
render,
|
||||
task_recv,
|
||||
}
|
||||
}
|
||||
|
||||
fn event(&mut self, event: Self::Event, _: &ActiveEventLoop) {
|
||||
self.state.event(event, &mut self.rsc, &mut self.render);
|
||||
self.state.event(event, &mut self.rsc);
|
||||
}
|
||||
|
||||
fn window_event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) {
|
||||
let Self {
|
||||
rsc,
|
||||
render,
|
||||
state,
|
||||
task_recv,
|
||||
} = self;
|
||||
@@ -290,7 +273,11 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
} else {
|
||||
"move"
|
||||
};
|
||||
let t_ms = cursor_state.time.duration_since(render.epoch()).as_millis() as u64;
|
||||
let render_state = rsc.ui.render_state();
|
||||
let t_ms = cursor_state
|
||||
.time
|
||||
.duration_since(render_state.get().epoch())
|
||||
.as_millis() as u64;
|
||||
crate::sense::log_input_event(
|
||||
action,
|
||||
cursor_state.pos.x,
|
||||
@@ -300,7 +287,10 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
);
|
||||
}
|
||||
let window_size = ui_state.window_size();
|
||||
render.run_sensors(rsc, state, cursor_state, window_size);
|
||||
let render_state = rsc.ui.render_state();
|
||||
render_state
|
||||
.get()
|
||||
.run_sensors(rsc, state, cursor_state, window_size);
|
||||
}
|
||||
let ui_state = state.default_state_mut();
|
||||
if old != ui_state.focus
|
||||
@@ -324,23 +314,25 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
if animating {
|
||||
ui_state.window.request_redraw();
|
||||
}
|
||||
render.update(&ui_state.root, rsc);
|
||||
ui_state.renderer.update(&mut rsc.ui, render);
|
||||
rsc.draw(&ui_state.root);
|
||||
ui_state.renderer.update(&mut rsc.ui);
|
||||
let mut parts = ui_state.renderer.draw();
|
||||
parts.total = frame_start.elapsed();
|
||||
crate::diagnostics::log_frame(render, frame_start, parts, animating);
|
||||
if let Some(tree_update) = ui_state.access.update(rsc.widgets(), render, rsc) {
|
||||
let render_state = rsc.ui.render_state();
|
||||
let render_state = render_state.get();
|
||||
crate::diagnostics::log_frame(&render_state, frame_start, parts, animating);
|
||||
if let Some(tree_update) = ui_state.access.update(rsc.widgets(), &render_state, rsc)
|
||||
{
|
||||
ui_state.access_adapter.update_if_active(|| tree_update);
|
||||
}
|
||||
}
|
||||
WindowEvent::Resized(size) => {
|
||||
render.resize((size.width, size.height));
|
||||
rsc.ui.resize((size.width, size.height));
|
||||
ui_state.renderer.resize(size)
|
||||
}
|
||||
WindowEvent::ScaleFactorChanged { .. } => {
|
||||
let scale = content_scale(ui_state.window.as_ref());
|
||||
rsc.ui.text.density = scale;
|
||||
render.set_density(scale);
|
||||
rsc.ui.set_density(scale);
|
||||
ui_state.window.request_redraw();
|
||||
}
|
||||
WindowEvent::KeyboardInput { event, .. } => {
|
||||
@@ -422,16 +414,20 @@ impl<State: DefaultAppState> AppState for DefaultApp<State> {
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
state.window_event(event, rsc, render);
|
||||
state.window_event(event, rsc);
|
||||
let ui_state = self.state.default_state_mut();
|
||||
if render.needs_redraw(&ui_state.root, rsc.widgets()) {
|
||||
let render_state = rsc.ui.render_state();
|
||||
if render_state
|
||||
.get()
|
||||
.needs_redraw(&ui_state.root, rsc.widgets())
|
||||
{
|
||||
ui_state.renderer.window().request_redraw();
|
||||
}
|
||||
ui_state.input.end_frame();
|
||||
}
|
||||
|
||||
fn exit(&mut self) {
|
||||
self.state.exit(&mut self.rsc, &mut self.render);
|
||||
self.state.exit(&mut self.rsc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::task::RequestRedraw;
|
||||
use iris_core::{FrameParts, LinearRgba, UiData, UiRenderNode, UiRenderState, util::Vec2};
|
||||
use iris_core::{FrameParts, LinearRgba, Ui, UiRenderNode, util::Vec2};
|
||||
use pollster::FutureExt;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
@@ -26,8 +26,8 @@ pub struct UiRenderer {
|
||||
}
|
||||
|
||||
impl UiRenderer {
|
||||
pub fn update(&mut self, ui: &mut UiData, render: &mut UiRenderState) {
|
||||
self.ui.update(&self.device, &self.queue, ui, render);
|
||||
pub fn update(&mut self, ui: &mut Ui) {
|
||||
self.ui.update(&self.device, &self.queue, ui);
|
||||
}
|
||||
|
||||
/// The two waits, so a desktop frame divides up the same way an
|
||||
|
||||
+12
-13
@@ -168,7 +168,7 @@ impl OpenUrl for HarnessState {
|
||||
/// `AndroidRsc` minus the windowing, for the same reason those two are
|
||||
/// separate types (`AndroidRsc`'s own doc).
|
||||
pub struct HarnessRsc {
|
||||
pub ui: UiData,
|
||||
pub ui: Ui,
|
||||
pub events: EventManager<Self>,
|
||||
pub tasks: Tasks<Self>,
|
||||
pub state: WidgetState,
|
||||
@@ -176,10 +176,10 @@ pub struct HarnessRsc {
|
||||
}
|
||||
|
||||
impl UiRsc for HarnessRsc {
|
||||
fn ui(&self) -> &UiData {
|
||||
fn ui(&self) -> &Ui {
|
||||
&self.ui
|
||||
}
|
||||
fn ui_mut(&mut self) -> &mut UiData {
|
||||
fn ui_mut(&mut self) -> &mut Ui {
|
||||
&mut self.ui
|
||||
}
|
||||
fn on_draw(&mut self, active: &ActiveData) {
|
||||
@@ -239,7 +239,6 @@ impl<I: RscIdx<HarnessRsc>> std::ops::IndexMut<I> for HarnessRsc {
|
||||
/// the pointer, all advanced by the caller. See the module doc.
|
||||
pub struct Harness {
|
||||
pub rsc: HarnessRsc,
|
||||
pub render: UiRenderState,
|
||||
pub state: HarnessState,
|
||||
task_recv: TaskMsgReceiver<HarnessRsc>,
|
||||
redraws: Arc<RedrawCounter>,
|
||||
@@ -258,19 +257,16 @@ impl Harness {
|
||||
let redraws = Arc::new(RedrawCounter::default());
|
||||
let (tasks, task_recv) = Tasks::init(redraws.clone());
|
||||
let mut rsc = HarnessRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
tasks,
|
||||
state: WidgetState::default(),
|
||||
_state: PhantomData,
|
||||
};
|
||||
rsc.ui.text.density = density;
|
||||
let mut render = UiRenderState::new();
|
||||
render.set_density(density);
|
||||
render.resize(size);
|
||||
rsc.ui.set_density(density);
|
||||
rsc.ui.resize(size);
|
||||
Self {
|
||||
rsc,
|
||||
render,
|
||||
state: HarnessState::new(),
|
||||
task_recv,
|
||||
redraws,
|
||||
@@ -302,15 +298,16 @@ impl Harness {
|
||||
let now = self.at(t_ms);
|
||||
let at = Instant::now();
|
||||
let animating = self.rsc.ui.tick_animations(now);
|
||||
self.render.update(&self.state.root, &mut self.rsc);
|
||||
self.rsc.draw(&self.state.root);
|
||||
// No GPU here, so there is nothing to acquire and nothing to
|
||||
// submit: the frame is all `build`, which is honest rather than
|
||||
// zero-filled (`FrameParts::whole`). `layout`/`redraw`/
|
||||
// `primitives` are still real, because `render.update` just ran;
|
||||
// see `iris::diagnostics::log_frame`'s own doc for why this reads
|
||||
// those back rather than timing anything itself.
|
||||
let render_state = self.rsc.ui.render_state();
|
||||
crate::diagnostics::log_frame(
|
||||
&self.render,
|
||||
&render_state.get(),
|
||||
now,
|
||||
FrameParts::whole(at.elapsed()),
|
||||
animating,
|
||||
@@ -344,7 +341,9 @@ impl Harness {
|
||||
}
|
||||
crate::sense::log_input_event(action.word(), pos.x, pos.y, t_ms, &[]);
|
||||
let cursor = self.cursor.clone();
|
||||
self.render
|
||||
let render_state = self.rsc.ui.render_state();
|
||||
render_state
|
||||
.get()
|
||||
.run_sensors(&mut self.rsc, &mut self.state, cursor, self.size);
|
||||
self.frame(t_ms);
|
||||
self.cursor.end_frame();
|
||||
|
||||
+28
-78
@@ -2,14 +2,14 @@ use crate::prelude::*;
|
||||
use std::{cell::Cell, cell::RefCell, rc::Rc};
|
||||
|
||||
pub(crate) struct TestRsc {
|
||||
pub(crate) ui: UiData,
|
||||
pub(crate) ui: Ui,
|
||||
}
|
||||
|
||||
impl UiRsc for TestRsc {
|
||||
fn ui(&self) -> &UiData {
|
||||
fn ui(&self) -> &Ui {
|
||||
&self.ui
|
||||
}
|
||||
fn ui_mut(&mut self) -> &mut UiData {
|
||||
fn ui_mut(&mut self) -> &mut Ui {
|
||||
&mut self.ui
|
||||
}
|
||||
}
|
||||
@@ -87,9 +87,7 @@ impl Widget for TracedParent {
|
||||
|
||||
#[test]
|
||||
fn a_widget_retains_its_entry_layer_not_its_child_cursor() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let back = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let front = rsc.ui.widgets.add_strong(Rect::new(PaintId::RED));
|
||||
let stack = rsc.ui.widgets.add_strong(Stack {
|
||||
@@ -125,9 +123,7 @@ fn a_widget_retains_its_entry_layer_not_its_child_cursor() {
|
||||
|
||||
#[test]
|
||||
fn a_size_dependent_parent_is_invalidated_before_layout_runs_downward() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let trace = Rc::new(RefCell::new(Vec::new()));
|
||||
let child = rsc.ui.widgets.add_strong(TracedLeaf {
|
||||
height: 20.0,
|
||||
@@ -155,9 +151,7 @@ fn a_size_dependent_parent_is_invalidated_before_layout_runs_downward() {
|
||||
|
||||
#[test]
|
||||
fn a_parent_that_ignores_child_size_is_not_invalidated_with_it() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let trace = Rc::new(RefCell::new(Vec::new()));
|
||||
let child = rsc.ui.widgets.add_strong(TracedLeaf {
|
||||
height: 20.0,
|
||||
@@ -183,9 +177,7 @@ fn a_parent_that_ignores_child_size_is_not_invalidated_with_it() {
|
||||
|
||||
#[test]
|
||||
fn a_span_reuses_unchanged_sibling_sizes_when_only_its_along_extent_changes() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let changed_draws = Rc::new(Cell::new(0));
|
||||
let sibling_draws = Rc::new(Cell::new(0));
|
||||
let changed = rsc.ui.widgets.add_strong(CountedLeaf {
|
||||
@@ -230,9 +222,7 @@ fn a_span_reuses_unchanged_sibling_sizes_when_only_its_along_extent_changes() {
|
||||
|
||||
#[test]
|
||||
fn a_child_coordinate_offset_moves_only_the_child_subtree() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let child = rsc.ui.widgets.add_strong(FixedRect(40.0));
|
||||
let child_weak = child.weak();
|
||||
let parent = rsc.ui.widgets.add_strong(ChildOffset {
|
||||
@@ -274,9 +264,7 @@ fn a_child_coordinate_offset_moves_only_the_child_subtree() {
|
||||
|
||||
#[test]
|
||||
fn a_hinted_rest_draws_once_and_only_moves_the_fixed_child_after_it() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let first = rsc.ui.widgets.add_strong(FixedRect(40.0));
|
||||
let fill = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let fill = rsc.ui.widgets.add_strong(Sized {
|
||||
@@ -330,9 +318,7 @@ fn scrolled_rects(
|
||||
|
||||
#[test]
|
||||
fn an_unchanged_frame_draws_and_rewrites_nothing() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (_scroll, root, _rects) = scrolled_rects(&mut rsc, 500);
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((800.0, 20000.0));
|
||||
@@ -348,9 +334,7 @@ fn an_unchanged_frame_draws_and_rewrites_nothing() {
|
||||
|
||||
#[test]
|
||||
fn scrolling_moves_in_o1_without_a_redraw() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, _rects) = scrolled_rects(&mut rsc, 500);
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((800.0, 600.0));
|
||||
@@ -370,9 +354,7 @@ fn scrolling_moves_in_o1_without_a_redraw() {
|
||||
|
||||
#[test]
|
||||
fn hit_testing_follows_a_scrolled_widget() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, rects) = scrolled_rects(&mut rsc, 500);
|
||||
let mut render = UiRenderState::new();
|
||||
render.resize((800.0, 600.0));
|
||||
@@ -398,9 +380,7 @@ fn hit_testing_follows_a_scrolled_widget() {
|
||||
|
||||
#[test]
|
||||
fn redrawing_a_masked_widget_does_not_nest_its_own_mask() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (_scroll, inner_root, _rects) = scrolled_rects(&mut rsc, 8);
|
||||
let masked = rsc.ui.widgets.add_strong(Masked {
|
||||
shape: None,
|
||||
@@ -424,9 +404,7 @@ fn redrawing_a_masked_widget_does_not_nest_its_own_mask() {
|
||||
|
||||
#[test]
|
||||
fn a_mask_stays_put_while_its_scrolled_content_moves() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, inner_root, _rects) = scrolled_rects(&mut rsc, 500);
|
||||
let masked = rsc.ui.widgets.add_strong(Masked {
|
||||
shape: None,
|
||||
@@ -473,9 +451,7 @@ fn composer_like_tree(rsc: &mut TestRsc) -> (WeakWidget<TextEdit>, StrongWidget)
|
||||
|
||||
#[test]
|
||||
fn composing_text_after_a_keyboard_resize_lands_in_the_bars_own_region() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (field, root) = composer_like_tree(&mut rsc);
|
||||
let mut render = UiRenderState::new();
|
||||
|
||||
@@ -515,9 +491,7 @@ fn composing_text_after_a_keyboard_resize_lands_in_the_bars_own_region() {
|
||||
|
||||
#[test]
|
||||
fn a_scroll_measures_the_box_it_was_offered_not_the_window() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let rect = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let tall = rsc.ui.widgets.add_strong(Sized {
|
||||
inner: rect.any(),
|
||||
@@ -565,9 +539,7 @@ fn a_scroll_measures_the_box_it_was_offered_not_the_window() {
|
||||
|
||||
#[test]
|
||||
fn a_panned_widgets_own_hit_box_moves_exactly_once() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let rect = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let tall = rsc.ui.widgets.add_strong(Sized {
|
||||
inner: rect.any(),
|
||||
@@ -601,9 +573,7 @@ fn a_panned_widgets_own_hit_box_moves_exactly_once() {
|
||||
|
||||
#[test]
|
||||
fn a_masked_widget_keeps_one_mask_slot_that_is_always_its_own_region() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (_scroll, inner_root, _rects) = scrolled_rects(&mut rsc, 8);
|
||||
let masked = rsc.ui.widgets.add_strong(Masked {
|
||||
shape: None,
|
||||
@@ -648,9 +618,7 @@ fn a_masked_widget_keeps_one_mask_slot_that_is_always_its_own_region() {
|
||||
|
||||
#[test]
|
||||
fn a_dp_cap_is_reported_in_pixels_so_a_span_can_place_it() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let rect = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let tall = rsc.ui.widgets.add_strong(Sized {
|
||||
inner: rect.any(),
|
||||
@@ -690,9 +658,7 @@ fn a_dp_cap_is_reported_in_pixels_so_a_span_can_place_it() {
|
||||
|
||||
#[test]
|
||||
fn a_size_independent_widget_moved_by_its_parent_has_the_hit_box_it_is_drawn_at() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let top = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let spacer = rsc.ui.widgets.add_strong(Sized {
|
||||
inner: top.any(),
|
||||
@@ -757,9 +723,7 @@ impl Widget for MoveThenPlace {
|
||||
|
||||
#[test]
|
||||
fn a_widget_moved_by_its_parent_and_then_placed_inside_it_lands_at_the_placement() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let rect = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let child = rsc.ui.widgets.add_strong(Sized {
|
||||
inner: rect.any(),
|
||||
@@ -839,9 +803,7 @@ fn rounded_container(rsc: &mut TestRsc) -> (UiRenderState, MaskIdx, WidgetId, u3
|
||||
|
||||
#[test]
|
||||
fn a_masked_child_is_clipped_by_its_container_s_own_corner() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (render, mask, _child, slot) = rounded_container(&mut rsc);
|
||||
let corners = render.primitive_corners(slot, &rsc);
|
||||
let radius = render
|
||||
@@ -879,9 +841,7 @@ fn a_masked_child_is_clipped_by_its_container_s_own_corner() {
|
||||
|
||||
#[test]
|
||||
fn a_mask_s_shape_decides_what_can_be_pressed() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (render, mask, _child, slot) = rounded_container(&mut rsc);
|
||||
let corners = render.primitive_corners(slot, &rsc);
|
||||
|
||||
@@ -907,9 +867,7 @@ fn a_mask_s_shape_decides_what_can_be_pressed() {
|
||||
|
||||
#[test]
|
||||
fn nested_masks_multiply_their_coverage() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let child = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let child_id = child.id();
|
||||
|
||||
@@ -970,9 +928,7 @@ fn nested_masks_multiply_their_coverage() {
|
||||
|
||||
#[test]
|
||||
fn a_plain_mask_still_clips_to_a_square_box() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (_scroll, inner_root, _rects) = scrolled_rects(&mut rsc, 8);
|
||||
let root = rsc
|
||||
.ui
|
||||
@@ -1002,9 +958,7 @@ fn a_plain_mask_still_clips_to_a_square_box() {
|
||||
#[test]
|
||||
fn a_scroll_area_opens_at_the_start_of_content_it_has_not_measured_yet() {
|
||||
for (name, pin, want) in [("read", Pin::Start, 0.0), ("written", Pin::End, 4900.0)] {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let fill = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE)).any();
|
||||
let tall = rsc.ui.widgets.add_strong(Sized {
|
||||
inner: fill,
|
||||
@@ -1037,9 +991,7 @@ fn a_span_of_padded_children_inside_a_span_draws_each_where_its_box_is() {
|
||||
const PAD: f32 = 4.0;
|
||||
const ROW: f32 = 20.0;
|
||||
const HEADER: f32 = 30.0;
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let header_fill = rsc.ui.widgets.add_strong(Rect::new(PaintId::RED)).any();
|
||||
let header_id = header_fill.id();
|
||||
let header = rsc.ui.widgets.add_strong(Sized {
|
||||
@@ -1120,9 +1072,7 @@ fn a_new_child_in_a_growing_lazy_row_uses_its_final_box_immediately() {
|
||||
const SECOND: f32 = 70.0;
|
||||
const GAP: f32 = 8.0;
|
||||
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let first = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let first_id = first.id();
|
||||
let first = rsc.ui.widgets.add_strong(Sized {
|
||||
|
||||
+6
-3
@@ -402,10 +402,11 @@ pub trait OverlayRscExt: HasEvents {
|
||||
where
|
||||
W: WidgetLike<Self, Tag>,
|
||||
{
|
||||
let render_handle = self.ui().render_state();
|
||||
let (target, path) = self
|
||||
.events()
|
||||
.controllers
|
||||
.path_to::<StackableOverlayController>(origin.id())?;
|
||||
.path_to::<StackableOverlayController>(origin.id(), &render_handle.get())?;
|
||||
clear_singles(&path, self);
|
||||
|
||||
let content = modal.add(self);
|
||||
@@ -447,10 +448,11 @@ pub trait OverlayRscExt: HasEvents {
|
||||
{
|
||||
match options.kind {
|
||||
OverlayKind::Single => {
|
||||
let render_handle = self.ui().render_state();
|
||||
let target = self
|
||||
.events()
|
||||
.controllers
|
||||
.nearest_id::<SingleOverlayController>(origin.id())?;
|
||||
.nearest_id::<SingleOverlayController>(origin.id(), &render_handle.get())?;
|
||||
let overlay = overlay.add_strong(self).any();
|
||||
self.with_controller(target, |single: &mut SingleOverlayController, rsc| {
|
||||
single.open(
|
||||
@@ -463,10 +465,11 @@ pub trait OverlayRscExt: HasEvents {
|
||||
})
|
||||
}
|
||||
OverlayKind::Stackable => {
|
||||
let render_handle = self.ui().render_state();
|
||||
let (target, path) = self
|
||||
.events()
|
||||
.controllers
|
||||
.path_to::<StackableOverlayController>(origin.id())?;
|
||||
.path_to::<StackableOverlayController>(origin.id(), &render_handle.get())?;
|
||||
clear_singles(&path, self);
|
||||
let overlay = overlay.add_strong(self).any();
|
||||
open_stackable_at(
|
||||
|
||||
+58
-11
@@ -2,15 +2,15 @@ use crate::prelude::*;
|
||||
use std::{cell::Cell, rc::Rc, time::Instant};
|
||||
|
||||
struct SenseRsc {
|
||||
ui: UiData,
|
||||
ui: Ui,
|
||||
events: EventManager<SenseRsc>,
|
||||
}
|
||||
|
||||
impl UiRsc for SenseRsc {
|
||||
fn ui(&self) -> &UiData {
|
||||
fn ui(&self) -> &Ui {
|
||||
&self.ui
|
||||
}
|
||||
fn ui_mut(&mut self) -> &mut UiData {
|
||||
fn ui_mut(&mut self) -> &mut Ui {
|
||||
&mut self.ui
|
||||
}
|
||||
fn on_draw(&mut self, active: &ActiveData) {
|
||||
@@ -28,6 +28,53 @@ impl HasState for SenseRsc {
|
||||
type State = ();
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct RenderProbe;
|
||||
|
||||
impl Event for RenderProbe {}
|
||||
|
||||
#[test]
|
||||
fn an_event_can_read_the_completed_frame_while_mutating_ui_data() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
rsc.ui.resize((100.0, 100.0));
|
||||
let widget = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let weak = widget.weak();
|
||||
let saw_active = Rc::new(Cell::new(false));
|
||||
rsc.register_event(weak, RenderProbe, {
|
||||
let saw_active = saw_active.clone();
|
||||
move |_, rsc| {
|
||||
let render_handle = rsc.ui().render_state();
|
||||
let render_state = render_handle.get();
|
||||
saw_active.set(render_state.active.contains_key(&weak.id()));
|
||||
rsc.widgets_mut().set_label(weak, "changed".to_string());
|
||||
assert!(render_state.active.contains_key(&weak.id()));
|
||||
}
|
||||
});
|
||||
rsc.draw(&widget.any());
|
||||
|
||||
rsc.run_event::<RenderProbe>(weak, (), &mut ());
|
||||
|
||||
assert!(saw_active.get());
|
||||
assert_eq!(rsc.widgets().label(weak), "changed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "render state cannot be mutated while it is being read")]
|
||||
fn an_event_cannot_start_a_draw() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
let widget = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE));
|
||||
let weak = widget.weak();
|
||||
rsc.register_event(weak, RenderProbe, |_, rsc| rsc.draw(None));
|
||||
|
||||
rsc.run_event::<RenderProbe>(weak, (), &mut ());
|
||||
}
|
||||
|
||||
impl HasEvents for SenseRsc {
|
||||
fn events(&self) -> &EventManager<Self> {
|
||||
&self.events
|
||||
@@ -50,7 +97,7 @@ fn cursor_at(pos: Vec2) -> CursorState {
|
||||
#[test]
|
||||
fn a_button_over_a_list_scrolls_the_list_and_still_clicks() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
|
||||
@@ -121,7 +168,7 @@ fn a_button_over_a_list_scrolls_the_list_and_still_clicks() {
|
||||
#[test]
|
||||
fn a_release_outside_every_hit_region_still_reaches_the_captured_widget() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
|
||||
@@ -180,7 +227,7 @@ fn a_release_outside_every_hit_region_still_reaches_the_captured_widget() {
|
||||
#[test]
|
||||
fn capturing_one_widget_starves_every_other_widget_of_events() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
|
||||
@@ -225,7 +272,7 @@ fn capturing_one_widget_starves_every_other_widget_of_events() {
|
||||
#[test]
|
||||
fn a_finger_drag_over_a_scroll_area_pans_it() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
|
||||
@@ -316,7 +363,7 @@ fn the_clock_orders_samples_across_events() {
|
||||
#[test]
|
||||
fn a_scroll_area_that_captured_the_pointer_learns_its_gesture_ended() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
let scroll_strong = rect(PaintId::WHITE)
|
||||
@@ -370,7 +417,7 @@ fn a_scroll_area_that_captured_the_pointer_learns_its_gesture_ended() {
|
||||
#[test]
|
||||
fn taking_the_pointer_cancels_everyone_else_tracking_the_press() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
|
||||
@@ -469,7 +516,7 @@ fn a_drag_pans_whichever_nested_scroll_area_owns_its_axis() {
|
||||
),
|
||||
] {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
let seen = Rc::new(Cell::new(None));
|
||||
@@ -526,7 +573,7 @@ fn a_drag_pans_whichever_nested_scroll_area_owns_its_axis() {
|
||||
#[test]
|
||||
fn a_press_does_not_reach_a_widget_the_pointer_has_just_left() {
|
||||
let mut rsc = SenseRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
|
||||
|
||||
@@ -833,14 +833,14 @@ mod tests {
|
||||
}
|
||||
|
||||
struct TestRsc {
|
||||
ui: UiData,
|
||||
ui: Ui,
|
||||
}
|
||||
|
||||
impl UiRsc for TestRsc {
|
||||
fn ui(&self) -> &UiData {
|
||||
fn ui(&self) -> &Ui {
|
||||
&self.ui
|
||||
}
|
||||
fn ui_mut(&mut self) -> &mut UiData {
|
||||
fn ui_mut(&mut self) -> &mut Ui {
|
||||
&mut self.ui
|
||||
}
|
||||
}
|
||||
@@ -882,9 +882,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_list_shorter_than_the_viewport_is_drawn_whole_and_stays_at_the_bottom() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
push_rows(&mut rsc, &mut list, &[0, 1, 2], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -912,9 +910,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_dir_up_span_grows_upward_from_item_zero() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::UP, Pin::End);
|
||||
let rows = push_rows(&mut rsc, &mut list, &[0, 1, 2], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -949,9 +945,7 @@ mod tests {
|
||||
#[test]
|
||||
fn a_delta_moves_both_directions_the_same_way_on_screen() {
|
||||
let moved_by = |dir: Dir| {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(dir, Pin::End);
|
||||
let keys: Vec<RowKey> = (0..10).collect();
|
||||
let rows = push_rows(&mut rsc, &mut list, &keys, 20.0);
|
||||
@@ -1003,9 +997,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_reversed_span_hit_tests_in_screen_space() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::UP, Pin::End);
|
||||
push_rows(&mut rsc, &mut list, &[0, 1, 2], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1030,9 +1022,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn bottom_anchored_by_default() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
push_rows(&mut rsc, &mut list, &[0, 1, 2, 3, 4], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1078,9 +1068,7 @@ mod tests {
|
||||
fn a_row_that_changes_height_draws_its_background_at_the_new_height_immediately() {
|
||||
for key_to_change in 0..5u64 {
|
||||
for new_height in [50.0f32, 8.0] {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
let mut rows = Vec::new();
|
||||
for key in 0..5u64 {
|
||||
@@ -1118,9 +1106,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_fill_shaped_background_is_not_left_oversized() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
let mut bg_ids = Vec::new();
|
||||
for key in 0..5u64 {
|
||||
@@ -1148,9 +1134,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn insert_above_anchor_is_o1_and_does_not_move_visible_rows() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
push_rows(&mut rsc, &mut list, &[10, 11, 12], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1188,9 +1172,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn expanding_a_row_holds_the_edge_nearest_the_tap() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
let rows = push_rows(&mut rsc, &mut list, &[0, 1, 2, 3, 4], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1234,9 +1216,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn expanding_a_row_holds_the_bottom_edge_when_tap_is_lower() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
let rows = push_rows(&mut rsc, &mut list, &[0, 1, 2, 3, 4], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1270,9 +1250,7 @@ mod tests {
|
||||
#[test]
|
||||
fn moves_stay_o1_across_list_size() {
|
||||
for &n in &[20usize, 200, 2000] {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
let keys: Vec<RowKey> = (0..n as u64).collect();
|
||||
push_rows(&mut rsc, &mut list, &keys, 20.0);
|
||||
@@ -1300,9 +1278,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_large_accumulated_offset_rebases_without_moving_the_content() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
let keys: Vec<RowKey> = (0..100).collect();
|
||||
let rows = push_rows(&mut rsc, &mut list, &keys, 1_000.0);
|
||||
@@ -1348,9 +1324,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn replacing_the_last_row_stays_pinned_to_the_bottom() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
push_rows(&mut rsc, &mut list, &[0, 1, 2, 3, 4], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1392,9 +1366,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn replace_back_forgets_the_evicted_keys_own_height() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
push_rows(&mut rsc, &mut list, &[0, 1, 2, 3, 4], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1429,9 +1401,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn replacing_the_last_row_out_of_view_does_not_move_visible_rows() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
push_rows(&mut rsc, &mut list, &[0, 1, 2, 3, 4], 20.0);
|
||||
let (list_weak, root) = add_list(&mut rsc, list);
|
||||
@@ -1474,9 +1444,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn replacing_the_last_row_many_times_does_not_leak_primitives() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
for key in 0..5u64 {
|
||||
let (_bg_id, row) = background_styled_row(&mut rsc, 20.0);
|
||||
@@ -1511,9 +1479,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn an_ancestor_redrawing_a_dirty_row_leaves_no_stale_copy() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let mut list = LazySpan::new(Dir::DOWN, Pin::End);
|
||||
let mut rows = Vec::new();
|
||||
for key in 0..5u64 {
|
||||
@@ -1574,9 +1540,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_fling_moves_the_list_and_then_settles() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, mut render) = build_flingable_list(&mut rsc);
|
||||
let list_weak = scroll;
|
||||
|
||||
@@ -1602,9 +1566,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_registered_fling_is_driven_by_tick_animations_and_then_unregisters() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, mut render) = build_flingable_list(&mut rsc);
|
||||
let list_weak = scroll;
|
||||
let before = scroll_position(rsc.ui.widgets.get(&list_weak).unwrap());
|
||||
@@ -1637,9 +1599,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_negative_delta_moves_toward_the_end() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, mut render) = build_flingable_list(&mut rsc);
|
||||
let list_weak = scroll;
|
||||
rsc.ui.widgets.get_mut(&scroll).unwrap().scroll(2000.0);
|
||||
@@ -1661,9 +1621,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn amt_counts_only_what_the_child_could_take() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, mut render) = build_flingable_list(&mut rsc);
|
||||
rsc.ui.widgets.get_mut(&scroll).unwrap().scroll(100.0);
|
||||
render.update(&root, &mut rsc);
|
||||
@@ -1684,9 +1642,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn a_fling_stops_at_the_first_row() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, mut render) = build_flingable_list(&mut rsc);
|
||||
let list_weak = scroll;
|
||||
rsc.ui.widgets.get_mut(&scroll).unwrap().fling(50_000.0);
|
||||
@@ -1710,9 +1666,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn scrolling_past_the_start_lands_on_it_in_the_same_frame() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (scroll, root, mut render) = build_flingable_list(&mut rsc);
|
||||
let list_weak = scroll;
|
||||
rsc.ui.widgets.get_mut(&scroll).unwrap().scroll(100_000.0);
|
||||
@@ -1734,9 +1688,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn anchor_position_display_reports_slot_and_offset() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let (list_weak, root, mut render) = build_flingable_list(&mut rsc);
|
||||
let _ = (&root, &mut render);
|
||||
let list_ref = rsc.ui.widgets.get(&list_weak).unwrap();
|
||||
|
||||
@@ -87,7 +87,6 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::layout_tests::TestRsc;
|
||||
use crate::sense::{CursorButton, DRAG_SLOP, PointerRequests};
|
||||
use iris_core::UiData;
|
||||
use std::time::Duration;
|
||||
|
||||
fn area() -> (Fixture, WidgetId) {
|
||||
@@ -95,9 +94,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn area_on(axis: Axis) -> (Fixture, WidgetId) {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let fill = rsc.ui.widgets.add_strong(Rect::new(PaintId::WHITE)).any();
|
||||
let id = fill.id();
|
||||
let long = Some(Len::abs(1000.0));
|
||||
|
||||
@@ -498,7 +498,7 @@ pub trait TextEditable {
|
||||
|
||||
impl<I: IdLike<Widget = TextEdit>> TextEditable for I {
|
||||
fn edit<'a>(&self, ui: &'a mut impl UiRsc) -> TextEditCtx<'a> {
|
||||
let ui = ui.ui_mut();
|
||||
let ui: &mut UiData = ui.ui_mut();
|
||||
TextEditCtx {
|
||||
text: ui.widgets.get_mut(self).unwrap(),
|
||||
data: &mut ui.text,
|
||||
|
||||
@@ -222,9 +222,7 @@ mod tests {
|
||||
use crate::prelude::*;
|
||||
|
||||
fn rendered_text(content: &str) -> (TestRsc, UiRenderState, WeakWidget<Text>, StrongWidget) {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let text = wtext(content).add_strong(&mut rsc);
|
||||
let id = text.weak();
|
||||
let root = text.any();
|
||||
@@ -306,9 +304,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn clearing_the_atlas_re_renders_cached_text_instead_of_reusing_it() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
};
|
||||
let mut rsc = TestRsc { ui: Ui::default() };
|
||||
let root = wtext("hello there")
|
||||
.size(18)
|
||||
.color(PaintId::WHITE)
|
||||
|
||||
@@ -161,7 +161,7 @@ pub trait TextSelectable {
|
||||
|
||||
impl<I: IdLike<Widget = Text>> TextSelectable for I {
|
||||
fn selection<'a>(&self, ui: &'a mut impl UiRsc) -> TextSelectionCtx<'a> {
|
||||
let ui = ui.ui_mut();
|
||||
let ui: &mut UiData = ui.ui_mut();
|
||||
TextSelectionCtx {
|
||||
view: &mut ui.widgets.get_mut(self).unwrap().view,
|
||||
data: &mut ui.text,
|
||||
@@ -250,7 +250,7 @@ impl SelectionController {
|
||||
id: WidgetId,
|
||||
f: impl FnOnce(&mut TextSelectionCtx<'_>) -> T,
|
||||
) -> Option<T> {
|
||||
let ui = rsc.ui_mut();
|
||||
let ui: &mut UiData = rsc.ui_mut();
|
||||
let text = ui
|
||||
.widgets
|
||||
.get_dyn_mut(id)?
|
||||
@@ -481,16 +481,16 @@ mod controller_tests {
|
||||
use super::*;
|
||||
|
||||
struct TestRsc {
|
||||
ui: UiData,
|
||||
ui: Ui,
|
||||
events: EventManager<TestRsc>,
|
||||
}
|
||||
|
||||
impl UiRsc for TestRsc {
|
||||
fn ui(&self) -> &UiData {
|
||||
fn ui(&self) -> &Ui {
|
||||
&self.ui
|
||||
}
|
||||
|
||||
fn ui_mut(&mut self) -> &mut UiData {
|
||||
fn ui_mut(&mut self) -> &mut Ui {
|
||||
&mut self.ui
|
||||
}
|
||||
|
||||
@@ -532,7 +532,7 @@ mod controller_tests {
|
||||
StrongWidget,
|
||||
) {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
let first = wtext("first").add(&mut rsc);
|
||||
@@ -571,7 +571,7 @@ mod controller_tests {
|
||||
#[test]
|
||||
fn a_widget_without_an_order_override_keeps_draw_order() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
let first = wtext("back").add(&mut rsc);
|
||||
@@ -604,7 +604,7 @@ mod controller_tests {
|
||||
#[test]
|
||||
fn nearest_controller_prefers_the_inner_scope() {
|
||||
let mut rsc = TestRsc {
|
||||
ui: UiData::default(),
|
||||
ui: Ui::default(),
|
||||
events: EventManager::default(),
|
||||
};
|
||||
let leaf = wtext("leaf").add(&mut rsc);
|
||||
@@ -624,7 +624,7 @@ mod controller_tests {
|
||||
let found = rsc
|
||||
.events()
|
||||
.controllers
|
||||
.nearest_id::<SelectionController>(leaf.id())
|
||||
.nearest_id::<SelectionController>(leaf.id(), &render)
|
||||
.unwrap();
|
||||
assert_eq!(found.host(), inner.id());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user