From dd9a7d30e54c1f21fa462806675f4e785ae12d89 Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Mon, 23 May 2022 19:52:12 +0200 Subject: [PATCH] refactor(core/rust/ui): expose page count to python [no changelog] --- core/embed/rust/librust_qstr.h | 1 + core/embed/rust/src/ui/component/base.rs | 13 +++++++++++++ core/embed/rust/src/ui/layout/obj.rs | 19 +++++++++++++++++++ .../rust/src/ui/model_t1/component/page.rs | 1 + .../rust/src/ui/model_tr/component/page.rs | 1 + .../rust/src/ui/model_tt/component/page.rs | 2 ++ core/src/trezor/loop.py | 8 ++++++++ core/src/trezor/ui/layouts/common.py | 9 ++++++++- core/src/trezor/ui/layouts/tt_v2/__init__.py | 5 ++++- 9 files changed, 57 insertions(+), 2 deletions(-) diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 705bb35e0..df3acc6f9 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -30,6 +30,7 @@ static void _librust_qstrs(void) { MP_QSTR_paint; MP_QSTR_trace; MP_QSTR_bounds; + MP_QSTR_page_count; MP_QSTR_title; MP_QSTR_action; diff --git a/core/embed/rust/src/ui/component/base.rs b/core/embed/rust/src/ui/component/base.rs index cfbad3404..88e499e04 100644 --- a/core/embed/rust/src/ui/component/base.rs +++ b/core/embed/rust/src/ui/component/base.rs @@ -314,6 +314,7 @@ pub struct EventCtx { place_requested: bool, paint_requested: bool, anim_frame_scheduled: bool, + page_count: Option, } impl EventCtx { @@ -338,6 +339,7 @@ impl EventCtx { paint_requested: false, /* We also need to paint, but this is supplemented by * `Child::marked_for_paint` being true. */ anim_frame_scheduled: false, + page_count: None, } } @@ -376,6 +378,16 @@ impl EventCtx { } } + pub fn set_page_count(&mut self, count: usize) { + #[cfg(feature = "ui_debug")] + assert!(self.page_count.is_none()); + self.page_count = Some(count); + } + + pub fn page_count(&self) -> Option { + self.page_count + } + pub fn pop_timer(&mut self) -> Option<(TimerToken, Duration)> { self.timers.pop() } @@ -384,6 +396,7 @@ impl EventCtx { self.place_requested = false; self.paint_requested = false; self.anim_frame_scheduled = false; + self.page_count = None; } fn register_timer(&mut self, token: TimerToken, deadline: Duration) { diff --git a/core/embed/rust/src/ui/layout/obj.rs b/core/embed/rust/src/ui/layout/obj.rs index 8054c073a..cde1d3293 100644 --- a/core/embed/rust/src/ui/layout/obj.rs +++ b/core/embed/rust/src/ui/layout/obj.rs @@ -112,6 +112,7 @@ struct LayoutObjInner { root: Gc, event_ctx: EventCtx, timer_fn: Obj, + page_count: u16, } impl LayoutObj { @@ -130,6 +131,7 @@ impl LayoutObj { root, event_ctx: EventCtx::new(), timer_fn: Obj::const_none(), + page_count: 1, }), }) } @@ -174,6 +176,10 @@ impl LayoutObj { } } + if let Some(count) = inner.event_ctx.page_count() { + inner.page_count = count as u16; + } + Ok(msg) } @@ -247,6 +253,10 @@ impl LayoutObj { .trace(&mut CallbackTracer(callback)); } + fn obj_page_count(&self) -> Obj { + self.inner.borrow().page_count.into() + } + #[cfg(feature = "ui_debug")] fn obj_bounds(&self) { use crate::ui::display; @@ -275,6 +285,7 @@ impl LayoutObj { Qstr::MP_QSTR_paint => obj_fn_1!(ui_layout_paint).as_obj(), Qstr::MP_QSTR_trace => obj_fn_2!(ui_layout_trace).as_obj(), Qstr::MP_QSTR_bounds => obj_fn_1!(ui_layout_bounds).as_obj(), + Qstr::MP_QSTR_page_count => obj_fn_1!(ui_layout_page_count).as_obj(), }), }; &TYPE @@ -411,6 +422,14 @@ extern "C" fn ui_layout_paint(this: Obj) -> Obj { unsafe { util::try_or_raise(block) } } +extern "C" fn ui_layout_page_count(this: Obj) -> Obj { + let block = || { + let this: Gc = this.try_into()?; + Ok(this.obj_page_count()) + }; + unsafe { util::try_or_raise(block) } +} + #[cfg(feature = "ui_debug")] #[no_mangle] pub extern "C" fn ui_debug_layout_type() -> &'static Type { diff --git a/core/embed/rust/src/ui/model_t1/component/page.rs b/core/embed/rust/src/ui/model_t1/component/page.rs index cf9598e72..cb65dacce 100644 --- a/core/embed/rust/src/ui/model_t1/component/page.rs +++ b/core/embed/rust/src/ui/model_t1/component/page.rs @@ -67,6 +67,7 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + ctx.set_page_count(self.scrollbar.page_count); if self.scrollbar.has_previous_page() { if let Some(ButtonMsg::Clicked) = self.prev.event(ctx, event) { // Scroll up. diff --git a/core/embed/rust/src/ui/model_tr/component/page.rs b/core/embed/rust/src/ui/model_tr/component/page.rs index cf9598e72..cb65dacce 100644 --- a/core/embed/rust/src/ui/model_tr/component/page.rs +++ b/core/embed/rust/src/ui/model_tr/component/page.rs @@ -67,6 +67,7 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + ctx.set_page_count(self.scrollbar.page_count); if self.scrollbar.has_previous_page() { if let Some(ButtonMsg::Clicked) = self.prev.event(ctx, event) { // Scroll up. diff --git a/core/embed/rust/src/ui/model_tt/component/page.rs b/core/embed/rust/src/ui/model_tt/component/page.rs index 7664ba78d..96ca42e64 100644 --- a/core/embed/rust/src/ui/model_tt/component/page.rs +++ b/core/embed/rust/src/ui/model_tt/component/page.rs @@ -99,6 +99,7 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + ctx.set_page_count(self.scrollbar.page_count); if let Some(swipe) = self.swipe.event(ctx, event) { match swipe { SwipeDirection::Up => { @@ -339,6 +340,7 @@ mod tests { TouchEvent::TouchMove(p) }; component.event(&mut ctx, Event::Touch(ev)); + ctx.clear(); first = false; } } diff --git a/core/src/trezor/loop.py b/core/src/trezor/loop.py index 7a803c295..bb7d9c212 100644 --- a/core/src/trezor/loop.py +++ b/core/src/trezor/loop.py @@ -577,11 +577,19 @@ class spawn(Syscall): class Timer(Syscall): def __init__(self) -> None: self.task: Task | None = None + # Event::Attach is evaluated before task is set. Use this list to + # buffer timers until task is set. + self.before_task: list[tuple[int, Any]] = [] def handle(self, task: Task) -> None: self.task = task + for deadline, value in self.before_task: + schedule(self.task, value, deadline) + self.before_task.clear() def schedule(self, deadline: int, value: Any) -> None: deadline = utime.ticks_add(utime.ticks_ms(), deadline) if self.task is not None: schedule(self.task, value, deadline) + else: + self.before_task.append((deadline, value)) diff --git a/core/src/trezor/ui/layouts/common.py b/core/src/trezor/ui/layouts/common.py index 6ce6abd32..1fbeba029 100644 --- a/core/src/trezor/ui/layouts/common.py +++ b/core/src/trezor/ui/layouts/common.py @@ -16,11 +16,15 @@ async def button_request( ctx: wire.GenericContext, br_type: str, code: ButtonRequestType = ButtonRequestType.Other, + pages: int | None = None, ) -> None: if __debug__: log.debug(__name__, "ButtonRequest.type=%s", br_type) workflow.close_others() - await ctx.call(ButtonRequest(code=code), ButtonAck) + if pages is not None: + await ctx.call(ButtonRequest(code=code, pages=pages), ButtonAck) + else: + await ctx.call(ButtonRequest(code=code), ButtonAck) async def interact( @@ -34,6 +38,9 @@ async def interact( assert isinstance(layout, Paginated) return await layout.interact(ctx, code=br_code) + elif hasattr(layout, "page_count") and layout.page_count() > 1: # type: ignore [Cannot access member "page_count" for type "LayoutType"] + await button_request(ctx, br_type, br_code, pages=layout.page_count()) # type: ignore [Cannot access member "page_count" for type "LayoutType"] + return await ctx.wait(layout) else: await button_request(ctx, br_type, br_code) return await ctx.wait(layout) diff --git a/core/src/trezor/ui/layouts/tt_v2/__init__.py b/core/src/trezor/ui/layouts/tt_v2/__init__.py index c7a0fdb37..70ec7c5e6 100644 --- a/core/src/trezor/ui/layouts/tt_v2/__init__.py +++ b/core/src/trezor/ui/layouts/tt_v2/__init__.py @@ -19,6 +19,7 @@ class _RustLayout(ui.Layout): def __init__(self, layout: Any): self.layout = layout self.timer = loop.Timer() + self.layout.attach_timer_fn(self.set_timer) def set_timer(self, token: int, deadline: int) -> None: self.timer.schedule(deadline, token) @@ -71,7 +72,6 @@ class _RustLayout(ui.Layout): def handle_input_and_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator] touch = loop.wait(io.TOUCH) self._before_render() - self.layout.attach_timer_fn(self.set_timer) self.layout.paint() # self.layout.bounds() while True: @@ -95,6 +95,9 @@ class _RustLayout(ui.Layout): if msg is not None: raise ui.Result(msg) + def page_count(self) -> int: + return self.layout.page_count() + async def confirm_action( ctx: wire.GenericContext,