mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-04 13:52:35 +00:00
refactor(core/ui): clear display on rust side
[no changelog]
This commit is contained in:
parent
d8e7c00087
commit
d99e1eedd2
@ -47,17 +47,6 @@ STATIC mp_obj_t mod_trezorui_Display_make_new(const mp_obj_type_t *type,
|
|||||||
return MP_OBJ_FROM_PTR(o);
|
return MP_OBJ_FROM_PTR(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// def clear(self) -> None:
|
|
||||||
/// """
|
|
||||||
/// Clear display with black color.
|
|
||||||
/// """
|
|
||||||
STATIC mp_obj_t mod_trezorui_Display_clear(mp_obj_t self) {
|
|
||||||
display_clear();
|
|
||||||
return mp_const_none;
|
|
||||||
}
|
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_clear_obj,
|
|
||||||
mod_trezorui_Display_clear);
|
|
||||||
|
|
||||||
/// def refresh(self) -> None:
|
/// def refresh(self) -> None:
|
||||||
/// """
|
/// """
|
||||||
/// Refresh display (update screen).
|
/// Refresh display (update screen).
|
||||||
@ -161,7 +150,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_clear_save_obj,
|
|||||||
mod_trezorui_Display_clear_save);
|
mod_trezorui_Display_clear_save);
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = {
|
STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = {
|
||||||
{MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&mod_trezorui_Display_clear_obj)},
|
|
||||||
{MP_ROM_QSTR(MP_QSTR_refresh),
|
{MP_ROM_QSTR(MP_QSTR_refresh),
|
||||||
MP_ROM_PTR(&mod_trezorui_Display_refresh_obj)},
|
MP_ROM_PTR(&mod_trezorui_Display_refresh_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&mod_trezorui_Display_bar_obj)},
|
{MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&mod_trezorui_Display_bar_obj)},
|
||||||
|
@ -290,6 +290,7 @@ fn generate_trezorhal_bindings() {
|
|||||||
.allowlist_function("storage_set_counter")
|
.allowlist_function("storage_set_counter")
|
||||||
.allowlist_function("storage_next_counter")
|
.allowlist_function("storage_next_counter")
|
||||||
// display
|
// display
|
||||||
|
.allowlist_function("display_clear")
|
||||||
.allowlist_function("display_offset")
|
.allowlist_function("display_offset")
|
||||||
.allowlist_function("display_refresh")
|
.allowlist_function("display_refresh")
|
||||||
.allowlist_function("display_backlight")
|
.allowlist_function("display_backlight")
|
||||||
|
@ -174,3 +174,9 @@ pub fn refresh() {
|
|||||||
ffi::display_refresh();
|
ffi::display_refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear() {
|
||||||
|
unsafe {
|
||||||
|
ffi::display_clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
ui::{
|
ui::{
|
||||||
component::{maybe::PaintOverlapping, MsgMap},
|
component::{maybe::PaintOverlapping, MsgMap},
|
||||||
display::Color,
|
display::{self, Color},
|
||||||
geometry::{Offset, Rect},
|
geometry::{Offset, Rect},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -191,6 +191,80 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Same as `Child` but also handles screen clearing when layout is first
|
||||||
|
/// painted.
|
||||||
|
pub struct Root<T> {
|
||||||
|
inner: Child<T>,
|
||||||
|
marked_for_clear: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Root<T> {
|
||||||
|
pub fn new(component: T) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Child::new(component),
|
||||||
|
marked_for_clear: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner(&self) -> &Child<T> {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skip_paint(&mut self) {
|
||||||
|
self.inner.skip_paint()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_screen(&mut self) {
|
||||||
|
self.marked_for_clear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Component for Root<T>
|
||||||
|
where
|
||||||
|
T: Component,
|
||||||
|
{
|
||||||
|
type Msg = T::Msg;
|
||||||
|
|
||||||
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
|
self.inner.place(bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
|
let msg = self.inner.event(ctx, event);
|
||||||
|
if ctx.needs_repaint_root() {
|
||||||
|
self.marked_for_clear = true;
|
||||||
|
let mut dummy_ctx = EventCtx::new();
|
||||||
|
let paint_msg = self.inner.event(&mut dummy_ctx, Event::RequestPaint);
|
||||||
|
assert!(matches!(paint_msg, None));
|
||||||
|
assert!(dummy_ctx.timers.is_empty());
|
||||||
|
}
|
||||||
|
msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(&mut self) {
|
||||||
|
if self.marked_for_clear && self.inner.will_paint() {
|
||||||
|
self.marked_for_clear = false;
|
||||||
|
display::clear()
|
||||||
|
}
|
||||||
|
self.inner.paint();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ui_bounds")]
|
||||||
|
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||||
|
self.inner.bounds(sink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ui_debug")]
|
||||||
|
impl<T> crate::trace::Trace for Root<T>
|
||||||
|
where
|
||||||
|
T: crate::trace::Trace,
|
||||||
|
{
|
||||||
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
|
self.inner.trace(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<M, T, U> Component for (T, U)
|
impl<M, T, U> Component for (T, U)
|
||||||
where
|
where
|
||||||
T: Component<Msg = M>,
|
T: Component<Msg = M>,
|
||||||
@ -379,6 +453,7 @@ pub struct EventCtx {
|
|||||||
paint_requested: bool,
|
paint_requested: bool,
|
||||||
anim_frame_scheduled: bool,
|
anim_frame_scheduled: bool,
|
||||||
page_count: Option<usize>,
|
page_count: Option<usize>,
|
||||||
|
root_repaint_requested: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventCtx {
|
impl EventCtx {
|
||||||
@ -404,6 +479,7 @@ impl EventCtx {
|
|||||||
* `Child::marked_for_paint` being true. */
|
* `Child::marked_for_paint` being true. */
|
||||||
anim_frame_scheduled: false,
|
anim_frame_scheduled: false,
|
||||||
page_count: None,
|
page_count: None,
|
||||||
|
root_repaint_requested: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,6 +518,14 @@ impl EventCtx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn request_repaint_root(&mut self) {
|
||||||
|
self.root_repaint_requested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn needs_repaint_root(&self) -> bool {
|
||||||
|
self.root_repaint_requested
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_page_count(&mut self, count: usize) {
|
pub fn set_page_count(&mut self, count: usize) {
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
assert!(self.page_count.is_none());
|
assert!(self.page_count.is_none());
|
||||||
@ -461,6 +545,7 @@ impl EventCtx {
|
|||||||
self.paint_requested = false;
|
self.paint_requested = false;
|
||||||
self.anim_frame_scheduled = false;
|
self.anim_frame_scheduled = false;
|
||||||
self.page_count = None;
|
self.page_count = None;
|
||||||
|
self.root_repaint_requested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_timer(&mut self, token: TimerToken, deadline: Duration) {
|
fn register_timer(&mut self, token: TimerToken, deadline: Duration) {
|
||||||
|
@ -16,7 +16,7 @@ pub mod qr_code;
|
|||||||
pub mod text;
|
pub mod text;
|
||||||
pub mod timeout;
|
pub mod timeout;
|
||||||
|
|
||||||
pub use base::{Child, Component, ComponentExt, Event, EventCtx, Never, TimerToken};
|
pub use base::{Child, Component, ComponentExt, Event, EventCtx, Never, Root, TimerToken};
|
||||||
pub use border::Border;
|
pub use border::Border;
|
||||||
pub use empty::Empty;
|
pub use empty::Empty;
|
||||||
pub use label::Label;
|
pub use label::Label;
|
||||||
|
@ -341,6 +341,11 @@ pub fn rect_fill_corners(r: Rect, fg_color: Color) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw black rectangle over entire screen.
|
||||||
|
pub fn clear() {
|
||||||
|
display::clear();
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct TextOverlay<T> {
|
pub struct TextOverlay<T> {
|
||||||
area: Rect,
|
area: Rect,
|
||||||
|
@ -17,7 +17,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
ui::{
|
ui::{
|
||||||
component::{Child, Component, Event, EventCtx, Never, TimerToken},
|
component::{Component, Event, EventCtx, Never, Root, TimerToken},
|
||||||
constant,
|
constant,
|
||||||
display::sync,
|
display::sync,
|
||||||
geometry::Rect,
|
geometry::Rect,
|
||||||
@ -49,9 +49,10 @@ pub trait ObjComponent: MaybeTrace {
|
|||||||
fn obj_paint(&mut self) -> bool;
|
fn obj_paint(&mut self) -> bool;
|
||||||
fn obj_bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
fn obj_bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
||||||
fn obj_skip_paint(&mut self) {}
|
fn obj_skip_paint(&mut self) {}
|
||||||
|
fn obj_request_clear(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ObjComponent for Child<T>
|
impl<T> ObjComponent for Root<T>
|
||||||
where
|
where
|
||||||
T: ComponentMsgObj + MaybeTrace,
|
T: ComponentMsgObj + MaybeTrace,
|
||||||
{
|
{
|
||||||
@ -61,14 +62,14 @@ where
|
|||||||
|
|
||||||
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error> {
|
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error> {
|
||||||
if let Some(msg) = self.event(ctx, event) {
|
if let Some(msg) = self.event(ctx, event) {
|
||||||
self.inner().msg_try_into_obj(msg)
|
self.inner().inner().msg_try_into_obj(msg)
|
||||||
} else {
|
} else {
|
||||||
Ok(Obj::const_none())
|
Ok(Obj::const_none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_paint(&mut self) -> bool {
|
fn obj_paint(&mut self) -> bool {
|
||||||
let will_paint = self.will_paint();
|
let will_paint = self.inner().will_paint();
|
||||||
self.paint();
|
self.paint();
|
||||||
will_paint
|
will_paint
|
||||||
}
|
}
|
||||||
@ -81,6 +82,10 @@ where
|
|||||||
fn obj_skip_paint(&mut self) {
|
fn obj_skip_paint(&mut self) {
|
||||||
self.skip_paint()
|
self.skip_paint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn obj_request_clear(&mut self) {
|
||||||
|
self.clear_screen()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `LayoutObj` is a GC-allocated object exported to MicroPython, with type
|
/// `LayoutObj` is a GC-allocated object exported to MicroPython, with type
|
||||||
@ -102,9 +107,9 @@ struct LayoutObjInner {
|
|||||||
impl LayoutObj {
|
impl LayoutObj {
|
||||||
/// Create a new `LayoutObj`, wrapping a root component.
|
/// Create a new `LayoutObj`, wrapping a root component.
|
||||||
pub fn new(root: impl ComponentMsgObj + MaybeTrace + 'static) -> Result<Gc<Self>, Error> {
|
pub fn new(root: impl ComponentMsgObj + MaybeTrace + 'static) -> Result<Gc<Self>, Error> {
|
||||||
// Let's wrap the root component into a `Child` to maintain the top-level
|
// Let's wrap the root component into a `Root` to maintain the top-level
|
||||||
// invalidation logic.
|
// invalidation logic.
|
||||||
let wrapped_root = Child::new(root);
|
let wrapped_root = Root::new(root);
|
||||||
// SAFETY: We are coercing GC-allocated sized ptr into an unsized one.
|
// SAFETY: We are coercing GC-allocated sized ptr into an unsized one.
|
||||||
let root =
|
let root =
|
||||||
unsafe { Gc::from_raw(Gc::into_raw(Gc::new(wrapped_root)?) as *mut dyn ObjComponent) };
|
unsafe { Gc::from_raw(Gc::into_raw(Gc::new(wrapped_root)?) as *mut dyn ObjComponent) };
|
||||||
@ -174,6 +179,12 @@ impl LayoutObj {
|
|||||||
Ok(msg)
|
Ok(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn obj_request_clear(&self) {
|
||||||
|
let mut inner = self.inner.borrow_mut();
|
||||||
|
// SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`.
|
||||||
|
unsafe { Gc::as_mut(&mut inner.root) }.obj_request_clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// Run a paint pass over the component tree. Returns true if any component
|
/// Run a paint pass over the component tree. Returns true if any component
|
||||||
/// actually requested painting since last invocation of the function.
|
/// actually requested painting since last invocation of the function.
|
||||||
fn obj_paint_if_requested(&self) -> bool {
|
fn obj_paint_if_requested(&self) -> bool {
|
||||||
@ -427,6 +438,7 @@ extern "C" fn ui_layout_request_complete_repaint(this: Obj) -> Obj {
|
|||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
panic!("cannot raise messages during RequestPaint");
|
panic!("cannot raise messages during RequestPaint");
|
||||||
};
|
};
|
||||||
|
this.obj_request_clear();
|
||||||
Ok(Obj::const_none())
|
Ok(Obj::const_none())
|
||||||
};
|
};
|
||||||
unsafe { util::try_or_raise(block) }
|
unsafe { util::try_or_raise(block) }
|
||||||
|
@ -18,11 +18,6 @@ class Display:
|
|||||||
Initialize the display.
|
Initialize the display.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def clear(self) -> None:
|
|
||||||
"""
|
|
||||||
Clear display with black color.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def refresh(self) -> None:
|
def refresh(self) -> None:
|
||||||
"""
|
"""
|
||||||
Refresh display (update screen).
|
Refresh display (update screen).
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
# pylint: disable=wrong-import-position
|
# pylint: disable=wrong-import-position
|
||||||
import utime
|
import utime
|
||||||
from micropython import const
|
|
||||||
from trezorui import Display
|
from trezorui import Display
|
||||||
from typing import TYPE_CHECKING, Any, Awaitable, Generator
|
from typing import TYPE_CHECKING, Any, Awaitable, Generator
|
||||||
|
|
||||||
from trezor import io, loop, utils, workflow
|
from trezor import loop, utils
|
||||||
|
|
||||||
# all rendering is done through a singleton of `Display`
|
# all rendering is done through a singleton of `Display`
|
||||||
display = Display()
|
display = Display()
|
||||||
@ -46,9 +45,6 @@ if utils.EMULATOR or utils.INTERNAL_MODEL in ("T1B1", "T2B1"):
|
|||||||
# import style later to avoid circular dep
|
# import style later to avoid circular dep
|
||||||
from trezor.ui import style # isort:skip
|
from trezor.ui import style # isort:skip
|
||||||
|
|
||||||
# import style definitions into namespace
|
|
||||||
from trezor.ui.style import * # isort:skip # noqa: F401,F403
|
|
||||||
|
|
||||||
|
|
||||||
async def _alert(count: int) -> None:
|
async def _alert(count: int) -> None:
|
||||||
short_sleep = loop.sleep(20)
|
short_sleep = loop.sleep(20)
|
||||||
@ -93,84 +89,6 @@ def backlight_fade(val: int, delay: int = 14000, step: int = 15) -> None:
|
|||||||
display.backlight(val)
|
display.backlight(val)
|
||||||
|
|
||||||
|
|
||||||
# Component events. Should be different from `io.TOUCH_*` events.
|
|
||||||
# Event dispatched when components should draw to the display, if they are
|
|
||||||
# marked for re-paint.
|
|
||||||
RENDER = const(-255)
|
|
||||||
# Event dispatched when components should mark themselves for re-painting.
|
|
||||||
REPAINT = const(-256)
|
|
||||||
|
|
||||||
# How long, in milliseconds, should the layout rendering task sleep between
|
|
||||||
# the render calls.
|
|
||||||
_RENDER_DELAY_MS = const(10)
|
|
||||||
|
|
||||||
|
|
||||||
class Component:
|
|
||||||
"""
|
|
||||||
Abstract class.
|
|
||||||
|
|
||||||
Components are GUI classes that inherit `Component` and form a tree, with a
|
|
||||||
`Layout` at the root, and other components underneath. Components that
|
|
||||||
have children, and therefore need to dispatch events to them, usually
|
|
||||||
override the `dispatch` method. Leaf components usually override the event
|
|
||||||
methods (`on_*`). Components signal a completion to the layout by raising
|
|
||||||
an instance of `Result`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.repaint = True
|
|
||||||
|
|
||||||
if utils.INTERNAL_MODEL in ("T2T1", "D001"):
|
|
||||||
|
|
||||||
def dispatch(self, event: int, x: int, y: int) -> None:
|
|
||||||
if event is RENDER:
|
|
||||||
self.on_render()
|
|
||||||
elif event is io.TOUCH_START:
|
|
||||||
self.on_touch_start(x, y)
|
|
||||||
elif event is io.TOUCH_MOVE:
|
|
||||||
self.on_touch_move(x, y)
|
|
||||||
elif event is io.TOUCH_END:
|
|
||||||
self.on_touch_end(x, y)
|
|
||||||
elif event is REPAINT:
|
|
||||||
self.repaint = True
|
|
||||||
|
|
||||||
def on_touch_start(self, x: int, y: int) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_touch_move(self, x: int, y: int) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_touch_end(self, x: int, y: int) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif utils.INTERNAL_MODEL in ("T1B1", "T2B1"):
|
|
||||||
|
|
||||||
def dispatch(self, event: int, x: int, y: int) -> None:
|
|
||||||
if event is RENDER:
|
|
||||||
self.on_render()
|
|
||||||
elif event is io.BUTTON_PRESSED:
|
|
||||||
self.on_button_pressed(x)
|
|
||||||
elif event is io.BUTTON_RELEASED:
|
|
||||||
self.on_button_released(x)
|
|
||||||
elif event is REPAINT:
|
|
||||||
self.repaint = True
|
|
||||||
|
|
||||||
def on_button_pressed(self, button_number: int) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_button_released(self, button_number: int) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_render(self) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if __debug__:
|
|
||||||
|
|
||||||
def read_content_into(self, content_store: list[str]) -> None:
|
|
||||||
content_store.clear()
|
|
||||||
content_store.append(self.__class__.__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class Result(Exception):
|
class Result(Exception):
|
||||||
"""
|
"""
|
||||||
When components want to trigger layout completion, they do so through
|
When components want to trigger layout completion, they do so through
|
||||||
@ -195,7 +113,7 @@ class Cancelled(Exception):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class Layout(Component):
|
class Layout:
|
||||||
"""
|
"""
|
||||||
Abstract class.
|
Abstract class.
|
||||||
|
|
||||||
@ -205,9 +123,6 @@ class Layout(Component):
|
|||||||
raised, usually from some of the child components.
|
raised, usually from some of the child components.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BACKLIGHT_LEVEL = style.BACKLIGHT_NORMAL
|
|
||||||
RENDER_SLEEP: loop.Syscall = loop.sleep(_RENDER_DELAY_MS)
|
|
||||||
|
|
||||||
async def __iter__(self) -> Any:
|
async def __iter__(self) -> Any:
|
||||||
"""
|
"""
|
||||||
Run the layout and wait until it completes. Returns the result value.
|
Run the layout and wait until it completes. Returns the result value.
|
||||||
@ -253,72 +168,13 @@ class Layout(Component):
|
|||||||
returns, the others are closed and `create_tasks` is called again.
|
returns, the others are closed and `create_tasks` is called again.
|
||||||
|
|
||||||
Usually overridden to add another tasks to the list."""
|
Usually overridden to add another tasks to the list."""
|
||||||
return self.handle_input(), self.handle_rendering()
|
raise NotImplementedError
|
||||||
|
|
||||||
if utils.INTERNAL_MODEL in ("T2T1", "D001"):
|
if __debug__:
|
||||||
|
|
||||||
def handle_input(self) -> Generator:
|
def read_content_into(self, content_store: list[str]) -> None:
|
||||||
"""Task that is waiting for the user input."""
|
content_store.clear()
|
||||||
touch = loop.wait(io.TOUCH)
|
content_store.append(self.__class__.__name__)
|
||||||
while True:
|
|
||||||
# Using `yield` instead of `await` to avoid allocations.
|
|
||||||
event, x, y = yield touch
|
|
||||||
workflow.idle_timer.touch()
|
|
||||||
self.dispatch(event, x, y)
|
|
||||||
# We dispatch a render event right after the touch. Quick and dirty
|
|
||||||
# way to get the lowest input-to-render latency.
|
|
||||||
self.dispatch(RENDER, 0, 0)
|
|
||||||
|
|
||||||
elif utils.INTERNAL_MODEL in ("T1B1", "T2B1"):
|
|
||||||
|
|
||||||
def handle_input(self) -> Generator:
|
|
||||||
"""Task that is waiting for the user input."""
|
|
||||||
button = loop.wait(io.BUTTON)
|
|
||||||
while True:
|
|
||||||
event, button_num = yield button
|
|
||||||
workflow.idle_timer.touch()
|
|
||||||
self.dispatch(event, button_num, 0)
|
|
||||||
self.dispatch(RENDER, 0, 0)
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise ValueError("Unknown Trezor model")
|
|
||||||
|
|
||||||
def _before_render(self) -> None:
|
|
||||||
# Before the first render, we dim the display.
|
|
||||||
backlight_fade(style.BACKLIGHT_NONE)
|
|
||||||
# Clear the screen of any leftovers, make sure everything is marked for
|
|
||||||
# repaint (we can be running the same layout instance multiple times)
|
|
||||||
# and paint it.
|
|
||||||
display.clear()
|
|
||||||
self.dispatch(REPAINT, 0, 0)
|
|
||||||
self.dispatch(RENDER, 0, 0)
|
|
||||||
|
|
||||||
if __debug__ and self.should_notify_layout_change:
|
|
||||||
from apps.debug import notify_layout_change
|
|
||||||
|
|
||||||
# notify about change and do not notify again until next await.
|
|
||||||
# (handle_rendering might be called multiple times in a single await,
|
|
||||||
# because of the endless loop in __iter__)
|
|
||||||
self.should_notify_layout_change = False
|
|
||||||
notify_layout_change(self)
|
|
||||||
|
|
||||||
# Display is usually refreshed after every loop step, but here we are
|
|
||||||
# rendering everything synchronously, so refresh it manually and turn
|
|
||||||
# the brightness on again.
|
|
||||||
refresh()
|
|
||||||
backlight_fade(self.BACKLIGHT_LEVEL)
|
|
||||||
|
|
||||||
def handle_rendering(self) -> loop.Task: # type: ignore [awaitable-is-generator]
|
|
||||||
"""Task that is rendering the layout in a busy loop."""
|
|
||||||
self._before_render()
|
|
||||||
sleep = self.RENDER_SLEEP
|
|
||||||
while True:
|
|
||||||
# Wait for a couple of ms and render the layout again. Because
|
|
||||||
# components use re-paint marking, they do not really draw on the
|
|
||||||
# display needlessly. Using `yield` instead of `await` to avoid allocations.
|
|
||||||
# TODO: remove the busy loop
|
|
||||||
yield sleep
|
|
||||||
self.dispatch(RENDER, 0, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def wait_until_layout_is_running() -> Awaitable[None]: # type: ignore [awaitable-is-generator]
|
def wait_until_layout_is_running() -> Awaitable[None]: # type: ignore [awaitable-is-generator]
|
||||||
|
@ -194,8 +194,6 @@ class RustLayout(ui.Layout):
|
|||||||
return self.handle_timers(), self.handle_input_and_rendering()
|
return self.handle_timers(), self.handle_input_and_rendering()
|
||||||
|
|
||||||
def _first_paint(self) -> None:
|
def _first_paint(self) -> None:
|
||||||
# Clear the screen of any leftovers.
|
|
||||||
ui.display.clear()
|
|
||||||
self._paint()
|
self._paint()
|
||||||
|
|
||||||
if __debug__ and self.should_notify_layout_change:
|
if __debug__ and self.should_notify_layout_change:
|
||||||
@ -253,7 +251,6 @@ def draw_simple(layout: Any) -> None:
|
|||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|
||||||
layout.attach_timer_fn(dummy_set_timer)
|
layout.attach_timer_fn(dummy_set_timer)
|
||||||
ui.display.clear()
|
|
||||||
layout.paint()
|
layout.paint()
|
||||||
ui.refresh()
|
ui.refresh()
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ class RustProgress:
|
|||||||
layout: Any,
|
layout: Any,
|
||||||
):
|
):
|
||||||
self.layout = layout
|
self.layout = layout
|
||||||
ui.display.clear()
|
|
||||||
self.layout.attach_timer_fn(self.set_timer)
|
self.layout.attach_timer_fn(self.set_timer)
|
||||||
self.layout.paint()
|
self.layout.paint()
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ if __debug__:
|
|||||||
|
|
||||||
|
|
||||||
class RustLayout(ui.Layout):
|
class RustLayout(ui.Layout):
|
||||||
|
BACKLIGHT_LEVEL = ui.style.BACKLIGHT_NORMAL
|
||||||
|
|
||||||
# pylint: disable=super-init-not-called
|
# pylint: disable=super-init-not-called
|
||||||
def __init__(self, layout: Any):
|
def __init__(self, layout: Any):
|
||||||
self.layout = layout
|
self.layout = layout
|
||||||
@ -160,9 +162,7 @@ class RustLayout(ui.Layout):
|
|||||||
return self.handle_timers(), self.handle_input_and_rendering()
|
return self.handle_timers(), self.handle_input_and_rendering()
|
||||||
|
|
||||||
def _first_paint(self) -> None:
|
def _first_paint(self) -> None:
|
||||||
# Clear the screen of any leftovers.
|
|
||||||
ui.backlight_fade(ui.style.BACKLIGHT_NONE)
|
ui.backlight_fade(ui.style.BACKLIGHT_NONE)
|
||||||
ui.display.clear()
|
|
||||||
self._paint()
|
self._paint()
|
||||||
|
|
||||||
if __debug__ and self.should_notify_layout_change:
|
if __debug__ and self.should_notify_layout_change:
|
||||||
@ -223,7 +223,6 @@ def draw_simple(layout: Any) -> None:
|
|||||||
|
|
||||||
layout.attach_timer_fn(dummy_set_timer)
|
layout.attach_timer_fn(dummy_set_timer)
|
||||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||||
ui.display.clear()
|
|
||||||
layout.paint()
|
layout.paint()
|
||||||
ui.refresh()
|
ui.refresh()
|
||||||
ui.backlight_fade(ui.style.BACKLIGHT_NORMAL)
|
ui.backlight_fade(ui.style.BACKLIGHT_NORMAL)
|
||||||
|
@ -86,7 +86,7 @@ class Homescreen(HomescreenBase):
|
|||||||
|
|
||||||
class Lockscreen(HomescreenBase):
|
class Lockscreen(HomescreenBase):
|
||||||
RENDER_INDICATOR = storage_cache.LOCKSCREEN_ON
|
RENDER_INDICATOR = storage_cache.LOCKSCREEN_ON
|
||||||
BACKLIGHT_LEVEL = ui.BACKLIGHT_LOW
|
BACKLIGHT_LEVEL = ui.style.BACKLIGHT_LOW
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -95,7 +95,7 @@ class Lockscreen(HomescreenBase):
|
|||||||
) -> None:
|
) -> None:
|
||||||
self.bootscreen = bootscreen
|
self.bootscreen = bootscreen
|
||||||
if bootscreen:
|
if bootscreen:
|
||||||
self.BACKLIGHT_LEVEL = ui.BACKLIGHT_NORMAL
|
self.BACKLIGHT_LEVEL = ui.style.BACKLIGHT_NORMAL
|
||||||
|
|
||||||
skip = (
|
skip = (
|
||||||
not bootscreen and storage_cache.homescreen_shown is self.RENDER_INDICATOR
|
not bootscreen and storage_cache.homescreen_shown is self.RENDER_INDICATOR
|
||||||
|
@ -16,7 +16,6 @@ class RustProgress:
|
|||||||
):
|
):
|
||||||
self.layout = layout
|
self.layout = layout
|
||||||
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
ui.backlight_fade(ui.style.BACKLIGHT_DIM)
|
||||||
ui.display.clear()
|
|
||||||
self.layout.attach_timer_fn(self.set_timer)
|
self.layout.attach_timer_fn(self.set_timer)
|
||||||
self.layout.paint()
|
self.layout.paint()
|
||||||
ui.backlight_fade(ui.style.BACKLIGHT_NORMAL)
|
ui.backlight_fade(ui.style.BACKLIGHT_NORMAL)
|
||||||
|
@ -5,9 +5,6 @@ from trezor.ui import display
|
|||||||
|
|
||||||
class TestDisplay(unittest.TestCase):
|
class TestDisplay(unittest.TestCase):
|
||||||
|
|
||||||
def test_clear(self):
|
|
||||||
display.clear()
|
|
||||||
|
|
||||||
def test_refresh(self):
|
def test_refresh(self):
|
||||||
display.refresh()
|
display.refresh()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user