mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-14 03:30:02 +00:00
refactor(core/ui): improve LayoutObj initialization
* RequestPaint message is sent at construction time to force calculation of number of pages * given that Attach corresponds to "start the layout" message, Child now responds to Attach the same way it responds to RequestPaint, by force-repainting everything.
This commit is contained in:
parent
b579796dd6
commit
98a6a2149c
@ -143,7 +143,7 @@ where
|
||||
// Handle the internal invalidation event here, so components don't have to. We
|
||||
// still pass it inside, so the event propagates correctly to all components in
|
||||
// the sub-tree.
|
||||
if let Event::RequestPaint = event {
|
||||
if matches!(event, Event::RequestPaint | Event::Attach(_)) {
|
||||
ctx.request_paint();
|
||||
}
|
||||
c.event(ctx, event)
|
||||
@ -371,8 +371,9 @@ pub enum Event {
|
||||
Timer(TimerToken),
|
||||
/// Advance progress bar. Progress screens only.
|
||||
Progress(u16, TString<'static>),
|
||||
/// Component has been attached to component tree. This event is sent once
|
||||
/// before any other events.
|
||||
/// Component has been attached to component tree, all children should
|
||||
/// prepare for painting and/or start their timers.
|
||||
/// This event is sent once before any other events.
|
||||
Attach(AttachType),
|
||||
/// Internally-handled event to inform all `Child` wrappers in a sub-tree to
|
||||
/// get scheduled for painting.
|
||||
@ -431,9 +432,8 @@ impl EventCtx {
|
||||
Self {
|
||||
timers: Vec::new(),
|
||||
next_token: Self::STARTING_TIMER_TOKEN,
|
||||
place_requested: true, // We need to perform a place pass in the beginning.
|
||||
paint_requested: false, /* We also need to paint, but this is supplemented by
|
||||
* `Child::marked_for_paint` being true. */
|
||||
place_requested: false,
|
||||
paint_requested: false,
|
||||
anim_frame_scheduled: false,
|
||||
page_count: None,
|
||||
button_request: None,
|
||||
@ -536,17 +536,13 @@ impl EventCtx {
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.place_requested = false;
|
||||
self.paint_requested = false;
|
||||
self.anim_frame_scheduled = false;
|
||||
self.page_count = None;
|
||||
#[cfg(feature = "ui_debug")]
|
||||
assert!(self.button_request.is_none());
|
||||
self.button_request = None;
|
||||
self.root_repaint_requested = false;
|
||||
self.swipe_disable_req = false;
|
||||
self.swipe_enable_req = false;
|
||||
self.transition_out = None;
|
||||
// replace self with a new instance, keeping only the fields we care about
|
||||
*self = Self {
|
||||
next_token: self.next_token,
|
||||
..Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn register_timer(&mut self, token: TimerToken, duration: Duration) {
|
||||
|
@ -128,6 +128,7 @@ where
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
|
||||
enum Repaint {
|
||||
None,
|
||||
Partial,
|
||||
@ -158,14 +159,22 @@ impl LayoutObjInner {
|
||||
pub fn new(root: impl ObjComponent + 'static) -> Result<Self, Error> {
|
||||
let root = GcBox::new(root)?;
|
||||
|
||||
Ok(Self {
|
||||
let mut new = Self {
|
||||
root: Some(gc::coerce!(ObjComponent, root)),
|
||||
event_ctx: EventCtx::new(),
|
||||
timer_fn: Obj::const_none(),
|
||||
page_count: 1,
|
||||
repaint: Repaint::Full,
|
||||
transition_out: AttachType::Initial,
|
||||
})
|
||||
};
|
||||
|
||||
// invoke the initial placement
|
||||
new.root_mut().obj_place(constant::screen());
|
||||
// cause a repaint pass to update the number of pages
|
||||
let msg = new.obj_event(Event::RequestPaint);
|
||||
assert!(matches!(msg, Ok(s) if s == Obj::const_none()));
|
||||
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn obj_delete(&mut self) {
|
||||
@ -188,14 +197,14 @@ impl LayoutObjInner {
|
||||
|
||||
fn obj_request_repaint(&mut self) {
|
||||
self.repaint = Repaint::Full;
|
||||
let mut dummy_ctx = EventCtx::new();
|
||||
let mut event_ctx = EventCtx::new();
|
||||
let paint_msg = self
|
||||
.root_mut()
|
||||
.obj_event(&mut dummy_ctx, Event::RequestPaint);
|
||||
.obj_event(&mut event_ctx, Event::RequestPaint);
|
||||
// paint_msg must not be an error and it must not return a result
|
||||
assert!(matches!(paint_msg, Ok(s) if s == Obj::const_none()));
|
||||
// there must be no timers set
|
||||
assert!(dummy_ctx.pop_timer().is_none());
|
||||
assert!(event_ctx.pop_timer().is_none());
|
||||
}
|
||||
|
||||
/// Run an event pass over the component tree. After the traversal, any
|
||||
@ -204,21 +213,22 @@ impl LayoutObjInner {
|
||||
/// an error, `Ok` with the message otherwise.
|
||||
fn obj_event(&mut self, event: Event) -> Result<Obj, Error> {
|
||||
let root = unwrap!(self.root.as_mut());
|
||||
// Place the root component on the screen in case it was previously requested.
|
||||
if self.event_ctx.needs_place() {
|
||||
root.obj_place(constant::screen());
|
||||
}
|
||||
|
||||
// Clear the leftover flags from the previous event pass.
|
||||
// Get the event context ready for a new event
|
||||
self.event_ctx.clear();
|
||||
|
||||
// Send the event down the component tree. Bail out in case of failure.
|
||||
let msg = root.obj_event(&mut self.event_ctx, event)?;
|
||||
|
||||
// Place the root component on the screen in case it was requested.
|
||||
if self.event_ctx.needs_place() {
|
||||
root.obj_place(constant::screen());
|
||||
}
|
||||
|
||||
// Check if we should repaint next time
|
||||
if self.event_ctx.needs_repaint_root() {
|
||||
self.obj_request_repaint();
|
||||
} else if self.event_ctx.needs_repaint() {
|
||||
} else if self.event_ctx.needs_repaint() && self.repaint == Repaint::None {
|
||||
self.repaint = Repaint::Partial;
|
||||
}
|
||||
|
||||
@ -236,10 +246,12 @@ impl LayoutObjInner {
|
||||
}
|
||||
}
|
||||
|
||||
// Update page count if it changed
|
||||
if let Some(count) = self.event_ctx.page_count() {
|
||||
self.page_count = count as u16;
|
||||
}
|
||||
|
||||
// Update outgoing transition if set
|
||||
if let Some(t) = self.event_ctx.get_transition_out() {
|
||||
self.transition_out = t;
|
||||
}
|
||||
@ -254,11 +266,6 @@ impl LayoutObjInner {
|
||||
display::clear();
|
||||
}
|
||||
|
||||
// Place the root component on the screen in case it was previously requested.
|
||||
if self.event_ctx.needs_place() {
|
||||
self.root_mut().obj_place(constant::screen());
|
||||
}
|
||||
|
||||
display::sync();
|
||||
|
||||
if self.repaint != Repaint::None {
|
||||
|
Loading…
Reference in New Issue
Block a user