From c257a8a687a3508b188517076fb90474ea9edd33 Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Mon, 25 Apr 2022 17:54:56 +0200 Subject: [PATCH] fix(core/ui/rust): painting of overlapping Maybe components [no changelog] --- core/embed/rust/src/ui/component/base.rs | 27 ++++++++++- core/embed/rust/src/ui/component/maybe.rs | 47 ++++++++++++++++++- core/embed/rust/src/ui/component/pad.rs | 12 +++++ .../model_tt/component/keyboard/mnemonic.rs | 6 +-- 4 files changed, 86 insertions(+), 6 deletions(-) diff --git a/core/embed/rust/src/ui/component/base.rs b/core/embed/rust/src/ui/component/base.rs index 8244147af..94224e445 100644 --- a/core/embed/rust/src/ui/component/base.rs +++ b/core/embed/rust/src/ui/component/base.rs @@ -4,7 +4,11 @@ use heapless::Vec; use crate::{ time::Duration, - ui::{component::Map, geometry::Rect}, + ui::{ + component::{maybe::PaintOverlapping, Map}, + display::Color, + geometry::Rect, + }, }; #[cfg(feature = "buttons")] @@ -136,6 +140,22 @@ where } } +impl PaintOverlapping for Child +where + T: PaintOverlapping, +{ + fn cleared_area(&self) -> Option<(Rect, Color)> { + self.component.cleared_area() + } + + fn paint_overlapping(&mut self) { + if self.marked_for_paint { + self.marked_for_paint = false; + self.component.paint_overlapping() + } + } +} + #[cfg(feature = "ui_debug")] impl crate::trace::Trace for Child where @@ -167,6 +187,11 @@ where self.0.paint(); self.1.paint(); } + + fn bounds(&self, sink: &mut dyn FnMut(Rect)) { + self.0.bounds(sink); + self.1.bounds(sink); + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/component/maybe.rs b/core/embed/rust/src/ui/component/maybe.rs index e6a44c32d..0c9f101c3 100644 --- a/core/embed/rust/src/ui/component/maybe.rs +++ b/core/embed/rust/src/ui/component/maybe.rs @@ -1,6 +1,6 @@ use crate::ui::{ component::{Component, ComponentExt, Event, EventCtx, Pad}, - display::Color, + display::{self, Color}, geometry::Rect, }; @@ -98,3 +98,48 @@ where self.inner.bounds(sink); } } + +pub trait PaintOverlapping { + /// Return area that would be cleared during regular paint, along with + /// background color, or None if clearing isn't requested. + fn cleared_area(&self) -> Option<(Rect, Color)>; + + /// Paint the component but do not clear background beforehand. + fn paint_overlapping(&mut self); +} + +impl PaintOverlapping for Maybe +where + T: Component, +{ + fn cleared_area(&self) -> Option<(Rect, Color)> { + self.pad.will_paint() + } + + fn paint_overlapping(&mut self) { + self.pad.cancel_clear(); + self.paint() + } +} + +/// Paint multiple Maybe components, correctly handling clearing of +/// background in the case the areas overlap, i.e. clear the combined area first +/// and then paint over it. +pub fn paint_overlapping(components: &mut [&mut dyn PaintOverlapping]) { + let mut area = Rect::zero(); + let mut color = Color::rgb(0, 0, 0); + for component in components.iter() { + if let Some((clear_area, clear_color)) = component.cleared_area() { + area = area.union(clear_area); + color = clear_color; + } + } + + if area != Rect::zero() { + display::rect_fill(area, color) + } + + for component in components.iter_mut() { + component.paint_overlapping() + } +} diff --git a/core/embed/rust/src/ui/component/pad.rs b/core/embed/rust/src/ui/component/pad.rs index b5e80aaa6..70a79707c 100644 --- a/core/embed/rust/src/ui/component/pad.rs +++ b/core/embed/rust/src/ui/component/pad.rs @@ -26,6 +26,18 @@ impl Pad { self.clear = true; } + pub fn cancel_clear(&mut self) { + self.clear = false; + } + + pub fn will_paint(&self) -> Option<(Rect, Color)> { + if self.clear { + Some((self.area, self.color)) + } else { + None + } + } + pub fn paint(&mut self) { if self.clear { self.clear = false; diff --git a/core/embed/rust/src/ui/model_tt/component/keyboard/mnemonic.rs b/core/embed/rust/src/ui/model_tt/component/keyboard/mnemonic.rs index 1ba286c2e..2732d7fc3 100644 --- a/core/embed/rust/src/ui/model_tt/component/keyboard/mnemonic.rs +++ b/core/embed/rust/src/ui/model_tt/component/keyboard/mnemonic.rs @@ -1,7 +1,7 @@ use core::ops::Deref; use crate::ui::{ - component::{Child, Component, Event, EventCtx, Label, Maybe}, + component::{maybe::paint_overlapping, Child, Component, Event, EventCtx, Label, Maybe}, geometry::{Alignment, Grid, Rect}, model_tt::{ component::{Button, ButtonMsg}, @@ -139,9 +139,7 @@ where } fn paint(&mut self) { - self.prompt.paint(); - self.input.paint(); - self.back.paint(); + paint_overlapping(&mut [&mut self.prompt, &mut self.input, &mut self.back]); for btn in &mut self.keys { btn.paint(); }