From 5378492ea975d2389bacddb32e7a2b8d51ea2e07 Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Fri, 14 Jan 2022 16:37:16 +0100 Subject: [PATCH] chore(core/rust): wireframe rendering for ui debugging [no changelog] --- core/embed/rust/librust_qstr.h | 1 + core/embed/rust/src/ui/component/base.rs | 7 +++- core/embed/rust/src/ui/component/map.rs | 5 +++ core/embed/rust/src/ui/component/pad.rs | 2 +- .../rust/src/ui/component/text/formatted.rs | 4 ++ .../rust/src/ui/component/text/paragraphs.rs | 14 +++---- core/embed/rust/src/ui/component/tuple.rs | 22 +++++----- core/embed/rust/src/ui/layout/obj.rs | 42 ++++++++++++++++++- .../rust/src/ui/model_tt/component/button.rs | 4 ++ .../rust/src/ui/model_tt/component/confirm.rs | 11 +++++ .../rust/src/ui/model_tt/component/dialog.rs | 6 +++ .../rust/src/ui/model_tt/component/frame.rs | 10 ++--- .../rust/src/ui/model_tt/component/page.rs | 18 ++++---- 13 files changed, 111 insertions(+), 35 deletions(-) diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index d451a3ea2..6847f288a 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -17,6 +17,7 @@ static void _librust_qstrs(void) { MP_QSTR_timer; MP_QSTR_paint; MP_QSTR_trace; + MP_QSTR_bounds; 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 387eab4bc..aa69f452c 100644 --- a/core/embed/rust/src/ui/component/base.rs +++ b/core/embed/rust/src/ui/component/base.rs @@ -2,11 +2,11 @@ use core::mem; use heapless::Vec; -use crate::time::Duration; #[cfg(feature = "model_t1")] use crate::ui::model_t1::event::ButtonEvent; #[cfg(feature = "model_tt")] use crate::ui::model_tt::event::TouchEvent; +use crate::{time::Duration, ui::geometry::Rect}; /// Type used by components that do not return any messages. /// @@ -20,6 +20,7 @@ pub trait Component { type Msg; fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option; fn paint(&mut self); + fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {} } /// Components should always avoid unnecessary overpaint to prevent obvious @@ -95,6 +96,10 @@ where self.component.paint(); } } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.component.bounds(sink) + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/component/map.rs b/core/embed/rust/src/ui/component/map.rs index 162e091b3..29e34ae53 100644 --- a/core/embed/rust/src/ui/component/map.rs +++ b/core/embed/rust/src/ui/component/map.rs @@ -1,4 +1,5 @@ use super::{Component, Event, EventCtx}; +use crate::ui::geometry::Rect; pub struct Map { inner: T, @@ -25,6 +26,10 @@ where fn paint(&mut self) { self.inner.paint() } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.inner.bounds(sink); + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/component/pad.rs b/core/embed/rust/src/ui/component/pad.rs index 670e1dd78..dcbff6d48 100644 --- a/core/embed/rust/src/ui/component/pad.rs +++ b/core/embed/rust/src/ui/component/pad.rs @@ -4,7 +4,7 @@ use crate::ui::{ }; pub struct Pad { - area: Rect, + pub area: Rect, color: Color, clear: bool, } diff --git a/core/embed/rust/src/ui/component/text/formatted.rs b/core/embed/rust/src/ui/component/text/formatted.rs index 06ce72426..bc7448e51 100644 --- a/core/embed/rust/src/ui/component/text/formatted.rs +++ b/core/embed/rust/src/ui/component/text/formatted.rs @@ -120,6 +120,10 @@ where fn paint(&mut self) { self.layout_content(&mut TextRenderer); } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + sink(self.layout.bounds) + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/component/text/paragraphs.rs b/core/embed/rust/src/ui/component/text/paragraphs.rs index 410593af2..a58c7b097 100644 --- a/core/embed/rust/src/ui/component/text/paragraphs.rs +++ b/core/embed/rust/src/ui/component/text/paragraphs.rs @@ -120,6 +120,13 @@ where char_offset = 0; } } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + sink(self.area); + for paragraph in self.list.iter().skip(self.offset.par).take(self.visible) { + sink(paragraph.layout.bounds) + } + } } impl Dimensions for Paragraphs { @@ -144,13 +151,6 @@ where } t.close(); } - - fn bounds(&self, sink: &dyn Fn(Rect)) { - sink(self.area); - for paragraph in self.list.iter().skip(self.offset.par).take(self.visible) { - paragraph.bounds(sink); - } - } } pub struct Paragraph { diff --git a/core/embed/rust/src/ui/component/tuple.rs b/core/embed/rust/src/ui/component/tuple.rs index 296408c92..1643943f0 100644 --- a/core/embed/rust/src/ui/component/tuple.rs +++ b/core/embed/rust/src/ui/component/tuple.rs @@ -18,6 +18,11 @@ where self.0.paint(); self.1.paint(); } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.0.bounds(sink); + self.1.bounds(sink); + } } impl Component for (A, B, C) @@ -40,6 +45,12 @@ where self.1.paint(); self.2.paint(); } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.0.bounds(sink); + self.1.bounds(sink); + self.2.bounds(sink); + } } #[cfg(feature = "ui_debug")] @@ -54,11 +65,6 @@ where t.field("1", &self.1); t.close(); } - - fn bounds(&self, sink: &dyn Fn(Rect)) { - self.0.bounds(sink); - self.1.bounds(sink); - } } #[cfg(feature = "ui_debug")] @@ -75,10 +81,4 @@ where t.field("2", &self.2); t.close(); } - - fn bounds(&self, sink: &dyn Fn(Rect)) { - self.0.bounds(sink); - self.1.bounds(sink); - self.2.bounds(sink); - } } diff --git a/core/embed/rust/src/ui/layout/obj.rs b/core/embed/rust/src/ui/layout/obj.rs index e9101f1f2..034777b58 100644 --- a/core/embed/rust/src/ui/layout/obj.rs +++ b/core/embed/rust/src/ui/layout/obj.rs @@ -13,7 +13,10 @@ use crate::{ typ::Type, }, time::Duration, - ui::component::{Child, Component, Event, EventCtx, Never, PageMsg, TimerToken}, + ui::{ + component::{Child, Component, Event, EventCtx, Never, PageMsg, TimerToken}, + geometry::Rect, + }, util, }; @@ -48,6 +51,7 @@ where pub trait ObjComponent { fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result; fn obj_paint(&mut self); + fn obj_bounds(&self, sink: &mut dyn FnMut(Rect)); } impl ObjComponent for Child @@ -65,6 +69,10 @@ where fn obj_paint(&mut self) { self.paint(); } + + fn obj_bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.bounds(sink) + } } #[cfg(feature = "ui_debug")] @@ -209,6 +217,22 @@ impl LayoutObj { .trace(&mut CallbackTracer(callback)); } + #[cfg(feature = "ui_debug")] + fn obj_bounds(&self) { + use crate::ui::display; + + // Sink for `Trace::bounds` that draws the boundaries using pseudorandom color. + fn wireframe(r: Rect) { + let w = r.width() as u16; + let h = r.height() as u16; + let color = display::Color::from_u16(w.rotate_right(w.into()).wrapping_add(h * 8)); + display::rect_stroke(r, color) + } + + wireframe(display::screen()); + self.inner.borrow().root.obj_bounds(&mut wireframe); + } + fn obj_type() -> &'static Type { static TYPE: Type = obj_type! { name: Qstr::MP_QSTR_Layout, @@ -219,6 +243,7 @@ impl LayoutObj { Qstr::MP_QSTR_timer => obj_fn_2!(ui_layout_timer).as_obj(), 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(), }), }; &TYPE @@ -384,3 +409,18 @@ extern "C" fn ui_layout_trace(this: Obj, callback: Obj) -> Obj { extern "C" fn ui_layout_trace(_this: Obj, _callback: Obj) -> Obj { Obj::const_none() } + +#[cfg(feature = "ui_debug")] +extern "C" fn ui_layout_bounds(this: Obj) -> Obj { + let block = || { + let this: Gc = this.try_into()?; + this.obj_bounds(); + Ok(Obj::const_none()) + }; + unsafe { util::try_or_raise(block) } +} + +#[cfg(not(feature = "ui_debug"))] +extern "C" fn ui_layout_bounds(_this: Obj) -> Obj { + Obj::const_none() +} diff --git a/core/embed/rust/src/ui/model_tt/component/button.rs b/core/embed/rust/src/ui/model_tt/component/button.rs index 88b50c416..b4eae66ea 100644 --- a/core/embed/rust/src/ui/model_tt/component/button.rs +++ b/core/embed/rust/src/ui/model_tt/component/button.rs @@ -209,6 +209,10 @@ where } } } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + sink(self.area) + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/model_tt/component/confirm.rs b/core/embed/rust/src/ui/model_tt/component/confirm.rs index 7aada94d6..7568c61a9 100644 --- a/core/embed/rust/src/ui/model_tt/component/confirm.rs +++ b/core/embed/rust/src/ui/model_tt/component/confirm.rs @@ -96,6 +96,17 @@ where self.cancel.paint(); self.confirm.paint(); } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + sink(self.pad.area); + if self.loader.is_animating() { + self.loader.bounds(sink) + } else { + self.content.bounds(sink) + } + self.cancel.bounds(sink); + self.confirm.bounds(sink); + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/model_tt/component/dialog.rs b/core/embed/rust/src/ui/model_tt/component/dialog.rs index 8071c7d1f..9bfa2b3f1 100644 --- a/core/embed/rust/src/ui/model_tt/component/dialog.rs +++ b/core/embed/rust/src/ui/model_tt/component/dialog.rs @@ -57,6 +57,12 @@ where self.left.paint(); self.right.paint(); } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.content.bounds(sink); + self.left.bounds(sink); + self.right.bounds(sink); + } } pub struct DialogLayout { diff --git a/core/embed/rust/src/ui/model_tt/component/frame.rs b/core/embed/rust/src/ui/model_tt/component/frame.rs index f025e2a27..72e9bc86c 100644 --- a/core/embed/rust/src/ui/model_tt/component/frame.rs +++ b/core/embed/rust/src/ui/model_tt/component/frame.rs @@ -58,6 +58,11 @@ where ); self.content.paint(); } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + sink(self.area); + self.content.bounds(sink); + } } #[cfg(feature = "ui_debug")] @@ -72,9 +77,4 @@ where t.field("content", &self.content); t.close(); } - - fn bounds(&self, sink: &dyn Fn(Rect)) { - sink(self.area); - self.content.bounds(sink); - } } 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 0ac163077..aedc50893 100644 --- a/core/embed/rust/src/ui/model_tt/component/page.rs +++ b/core/embed/rust/src/ui/model_tt/component/page.rs @@ -148,6 +148,15 @@ where display::fade_backlight(val); } } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + sink(self.scrollbar.area); + sink(self.pad.area); + self.content.bounds(sink); + if !self.scrollbar.has_next_page() { + self.buttons.bounds(sink); + } + } } #[cfg(feature = "ui_debug")] @@ -163,15 +172,6 @@ where t.field("content", &self.content); t.close(); } - - fn bounds(&self, sink: &dyn Fn(Rect)) { - sink(self.scrollbar.area); - sink(self.pad.area); - self.content.bounds(sink); - if !self.scrollbar.has_next_page() { - self.buttons.bounds(sink); - } - } } pub struct ScrollBar {