mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-04-25 19:49:02 +00:00
refactor(core/rust): introduce layout lifecycle states on Rust side
This commit is contained in:
parent
c8f3ebfa21
commit
df368413c6
@ -6,15 +6,18 @@
|
|||||||
|
|
||||||
static void _librust_qstrs(void) {
|
static void _librust_qstrs(void) {
|
||||||
MP_QSTR_;
|
MP_QSTR_;
|
||||||
|
MP_QSTR_ATTACHED;
|
||||||
MP_QSTR_AttachType;
|
MP_QSTR_AttachType;
|
||||||
MP_QSTR_BacklightLevels;
|
MP_QSTR_BacklightLevels;
|
||||||
MP_QSTR_CANCELLED;
|
MP_QSTR_CANCELLED;
|
||||||
MP_QSTR_CONFIRMED;
|
MP_QSTR_CONFIRMED;
|
||||||
MP_QSTR_DIM;
|
MP_QSTR_DIM;
|
||||||
|
MP_QSTR_DONE;
|
||||||
MP_QSTR_INFO;
|
MP_QSTR_INFO;
|
||||||
MP_QSTR_INITIAL;
|
MP_QSTR_INITIAL;
|
||||||
MP_QSTR_LOW;
|
MP_QSTR_LOW;
|
||||||
MP_QSTR_LayoutObj;
|
MP_QSTR_LayoutObj;
|
||||||
|
MP_QSTR_LayoutState;
|
||||||
MP_QSTR_MAX;
|
MP_QSTR_MAX;
|
||||||
MP_QSTR_MESSAGE_NAME;
|
MP_QSTR_MESSAGE_NAME;
|
||||||
MP_QSTR_MESSAGE_WIRE_TYPE;
|
MP_QSTR_MESSAGE_WIRE_TYPE;
|
||||||
@ -28,6 +31,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_SWIPE_RIGHT;
|
MP_QSTR_SWIPE_RIGHT;
|
||||||
MP_QSTR_SWIPE_UP;
|
MP_QSTR_SWIPE_UP;
|
||||||
MP_QSTR_TR;
|
MP_QSTR_TR;
|
||||||
|
MP_QSTR_TRANSITIONING;
|
||||||
MP_QSTR_TranslationsHeader;
|
MP_QSTR_TranslationsHeader;
|
||||||
MP_QSTR___del__;
|
MP_QSTR___del__;
|
||||||
MP_QSTR___dict__;
|
MP_QSTR___dict__;
|
||||||
@ -581,6 +585,7 @@ static void _librust_qstrs(void) {
|
|||||||
MP_QSTR_reset__wrong_word_selected;
|
MP_QSTR_reset__wrong_word_selected;
|
||||||
MP_QSTR_reset__you_need_one_share;
|
MP_QSTR_reset__you_need_one_share;
|
||||||
MP_QSTR_reset__your_backup_is_done;
|
MP_QSTR_reset__your_backup_is_done;
|
||||||
|
MP_QSTR_return_value;
|
||||||
MP_QSTR_reverse;
|
MP_QSTR_reverse;
|
||||||
MP_QSTR_rotation__change_template;
|
MP_QSTR_rotation__change_template;
|
||||||
MP_QSTR_rotation__east;
|
MP_QSTR_rotation__east;
|
||||||
|
@ -79,9 +79,9 @@ macro_rules! obj_fn_kw {
|
|||||||
/// Construct fixed static const `Map` from `key` => `val` pairs.
|
/// Construct fixed static const `Map` from `key` => `val` pairs.
|
||||||
macro_rules! obj_map {
|
macro_rules! obj_map {
|
||||||
($($key:expr => $val:expr),*) => ({
|
($($key:expr => $val:expr),*) => ({
|
||||||
Map::from_fixed_static(&[
|
$crate::micropython::map::Map::from_fixed_static(&[
|
||||||
$(
|
$(
|
||||||
Map::at($key, $val),
|
$crate::micropython::map::Map::at($key, $val),
|
||||||
)*
|
)*
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
@ -110,6 +110,7 @@ macro_rules! obj_dict {
|
|||||||
/// Compose a `Type` object definition.
|
/// Compose a `Type` object definition.
|
||||||
macro_rules! obj_type {
|
macro_rules! obj_type {
|
||||||
(name: $name:expr,
|
(name: $name:expr,
|
||||||
|
$(base: $base:expr,)?
|
||||||
$(locals: $locals:expr,)?
|
$(locals: $locals:expr,)?
|
||||||
$(make_new_fn: $make_new_fn:path,)?
|
$(make_new_fn: $make_new_fn:path,)?
|
||||||
$(attr_fn: $attr_fn:path,)?
|
$(attr_fn: $attr_fn:path,)?
|
||||||
@ -121,6 +122,11 @@ macro_rules! obj_type {
|
|||||||
|
|
||||||
let name = $name.to_u16();
|
let name = $name.to_u16();
|
||||||
|
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
#[allow(unused_assignments)]
|
||||||
|
let mut base_type: &'static ffi::mp_obj_type_t = &ffi::mp_type_type;
|
||||||
|
$(base_type = &$base;)?
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
#[allow(unused_assignments)]
|
#[allow(unused_assignments)]
|
||||||
let mut attr: ffi::mp_attr_fun_t = None;
|
let mut attr: ffi::mp_attr_fun_t = None;
|
||||||
@ -146,7 +152,7 @@ macro_rules! obj_type {
|
|||||||
|
|
||||||
ffi::mp_obj_type_t {
|
ffi::mp_obj_type_t {
|
||||||
base: ffi::mp_obj_base_t {
|
base: ffi::mp_obj_base_t {
|
||||||
type_: &ffi::mp_type_type,
|
type_: base_type,
|
||||||
},
|
},
|
||||||
flags: 0,
|
flags: 0,
|
||||||
name,
|
name,
|
||||||
|
@ -3,7 +3,7 @@ use num_traits::FromPrimitive;
|
|||||||
|
|
||||||
// ButtonRequestType from messages-common.proto
|
// ButtonRequestType from messages-common.proto
|
||||||
// Eventually this should be generated
|
// Eventually this should be generated
|
||||||
#[derive(Clone, Copy, FromPrimitive)]
|
#[derive(Clone, Copy, FromPrimitive, PartialEq, Eq)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
pub enum ButtonRequestCode {
|
pub enum ButtonRequestCode {
|
||||||
Other = 1,
|
Other = 1,
|
||||||
@ -41,7 +41,7 @@ impl ButtonRequestCode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct ButtonRequest {
|
pub struct ButtonRequest {
|
||||||
pub code: ButtonRequestCode,
|
pub code: ButtonRequestCode,
|
||||||
pub name: TString<'static>,
|
pub name: TString<'static>,
|
||||||
|
@ -14,9 +14,11 @@ use crate::{
|
|||||||
event::SwipeEvent,
|
event::SwipeEvent,
|
||||||
flow::{base::Decision, FlowController},
|
flow::{base::Decision, FlowController},
|
||||||
geometry::{Direction, Rect},
|
geometry::{Direction, Rect},
|
||||||
layout::obj::ObjComponent,
|
layout::base::{Layout, LayoutState},
|
||||||
shape::{render_on_display, ConcreteRenderer, Renderer, ScopedRenderer},
|
shape::{render_on_display, ConcreteRenderer, Renderer, ScopedRenderer},
|
||||||
|
ui_features::ModelUI,
|
||||||
util::animation_disabled,
|
util::animation_disabled,
|
||||||
|
UIFeaturesCommon,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,7 +110,11 @@ pub struct SwipeFlow {
|
|||||||
internal_pages: u16,
|
internal_pages: u16,
|
||||||
/// If triggering swipe by event, make this decision instead of default
|
/// If triggering swipe by event, make this decision instead of default
|
||||||
/// after the swipe.
|
/// after the swipe.
|
||||||
decision_override: Option<Decision>,
|
pending_decision: Option<Decision>,
|
||||||
|
/// Layout lifecycle state.
|
||||||
|
lifecycle_state: LayoutState,
|
||||||
|
/// Returned value from latest transition, stored as Obj.
|
||||||
|
returned_value: Option<Result<Obj, Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SwipeFlow {
|
impl SwipeFlow {
|
||||||
@ -120,7 +126,9 @@ impl SwipeFlow {
|
|||||||
allow_swipe: true,
|
allow_swipe: true,
|
||||||
internal_page_idx: 0,
|
internal_page_idx: 0,
|
||||||
internal_pages: 1,
|
internal_pages: 1,
|
||||||
decision_override: None,
|
pending_decision: None,
|
||||||
|
lifecycle_state: LayoutState::Initial,
|
||||||
|
returned_value: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,6 +177,7 @@ impl SwipeFlow {
|
|||||||
|
|
||||||
// reset and unlock swipe config
|
// reset and unlock swipe config
|
||||||
self.swipe = SwipeDetect::new();
|
self.swipe = SwipeDetect::new();
|
||||||
|
// unlock swipe events
|
||||||
self.allow_swipe = true;
|
self.allow_swipe = true;
|
||||||
|
|
||||||
// send an Attach event to the new page
|
// send an Attach event to the new page
|
||||||
@ -197,7 +206,7 @@ impl SwipeFlow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<FlowMsg> {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<LayoutState> {
|
||||||
let mut decision = Decision::Nothing;
|
let mut decision = Decision::Nothing;
|
||||||
let mut return_transition: AttachType = AttachType::Initial;
|
let mut return_transition: AttachType = AttachType::Initial;
|
||||||
|
|
||||||
@ -215,20 +224,21 @@ impl SwipeFlow {
|
|||||||
|
|
||||||
match self.swipe.event(ctx, event, config) {
|
match self.swipe.event(ctx, event, config) {
|
||||||
Some(SwipeEvent::End(dir)) => {
|
Some(SwipeEvent::End(dir)) => {
|
||||||
if let Some(override_decision) = self.decision_override.take() {
|
|
||||||
decision = override_decision;
|
|
||||||
} else {
|
|
||||||
decision = self.handle_swipe_child(ctx, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return_transition = AttachType::Swipe(dir);
|
return_transition = AttachType::Swipe(dir);
|
||||||
|
|
||||||
let new_internal_page_idx =
|
let new_internal_page_idx =
|
||||||
config.paging_event(dir, self.internal_page_idx, self.internal_pages);
|
config.paging_event(dir, self.internal_page_idx, self.internal_pages);
|
||||||
if new_internal_page_idx != self.internal_page_idx {
|
if new_internal_page_idx != self.internal_page_idx {
|
||||||
|
// internal paging event
|
||||||
self.internal_page_idx = new_internal_page_idx;
|
self.internal_page_idx = new_internal_page_idx;
|
||||||
decision = Decision::Nothing;
|
decision = Decision::Nothing;
|
||||||
attach = true;
|
attach = true;
|
||||||
|
} else if let Some(override_decision) = self.pending_decision.take() {
|
||||||
|
// end of simulated swipe, applying original decision
|
||||||
|
decision = override_decision;
|
||||||
|
} else {
|
||||||
|
// normal end-of-swipe event handling
|
||||||
|
decision = self.handle_swipe_child(ctx, dir);
|
||||||
}
|
}
|
||||||
Event::Swipe(SwipeEvent::End(dir))
|
Event::Swipe(SwipeEvent::End(dir))
|
||||||
}
|
}
|
||||||
@ -265,31 +275,36 @@ impl SwipeFlow {
|
|||||||
|
|
||||||
if let Decision::Transition(_, Swipe(direction)) = decision {
|
if let Decision::Transition(_, Swipe(direction)) = decision {
|
||||||
if config.is_allowed(direction) {
|
if config.is_allowed(direction) {
|
||||||
|
self.allow_swipe = true;
|
||||||
if !animation_disabled() {
|
if !animation_disabled() {
|
||||||
self.swipe.trigger(ctx, direction, config);
|
self.swipe.trigger(ctx, direction, config);
|
||||||
self.decision_override = Some(decision);
|
self.pending_decision = Some(decision);
|
||||||
decision = Decision::Nothing;
|
return Some(LayoutState::Transitioning(return_transition));
|
||||||
}
|
}
|
||||||
self.allow_swipe = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
//ignore message, we are already transitioning
|
//ignore message, we are already transitioning
|
||||||
self.current_page_mut().event(ctx, event);
|
let msg = self.current_page_mut().event(ctx, event);
|
||||||
|
assert!(msg.is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match decision {
|
match decision {
|
||||||
Decision::Transition(new_state, attach) => {
|
Decision::Transition(new_state, attach) => {
|
||||||
self.goto(ctx, new_state, attach);
|
self.goto(ctx, new_state, attach);
|
||||||
None
|
Some(LayoutState::Attached(ctx.button_request().take()))
|
||||||
}
|
}
|
||||||
Decision::Return(msg) => {
|
Decision::Return(msg) => {
|
||||||
ctx.set_transition_out(return_transition);
|
ctx.set_transition_out(return_transition);
|
||||||
self.swipe.reset();
|
self.swipe.reset();
|
||||||
self.allow_swipe = true;
|
self.allow_swipe = true;
|
||||||
Some(msg)
|
self.returned_value = Some(msg.try_into());
|
||||||
|
Some(LayoutState::Done)
|
||||||
|
}
|
||||||
|
Decision::Nothing if matches!(event, Event::Attach(_)) => {
|
||||||
|
Some(LayoutState::Attached(ctx.button_request().take()))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -307,23 +322,22 @@ impl SwipeFlow {
|
|||||||
/// This implementation relies on the fact that swipe components always return
|
/// This implementation relies on the fact that swipe components always return
|
||||||
/// `FlowMsg` as their `Component::Msg` (provided by `impl FlowComponentTrait`
|
/// `FlowMsg` as their `Component::Msg` (provided by `impl FlowComponentTrait`
|
||||||
/// earlier in this file).
|
/// earlier in this file).
|
||||||
#[cfg(feature = "micropython")]
|
impl Layout<Result<Obj, Error>> for SwipeFlow {
|
||||||
impl ObjComponent for SwipeFlow {
|
fn place(&mut self) {
|
||||||
fn obj_place(&mut self, bounds: Rect) -> Rect {
|
|
||||||
for elem in self.store.iter_mut() {
|
for elem in self.store.iter_mut() {
|
||||||
elem.place(bounds);
|
elem.place(ModelUI::SCREEN);
|
||||||
}
|
|
||||||
bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error> {
|
|
||||||
match self.event(ctx, event) {
|
|
||||||
None => Ok(Obj::const_none()),
|
|
||||||
Some(msg) => msg.try_into(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_paint(&mut self) {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<LayoutState> {
|
||||||
|
self.event(ctx, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value(&self) -> Option<&Result<Obj, Error>> {
|
||||||
|
self.returned_value.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(&mut self) {
|
||||||
render_on_display(None, Some(Color::black()), |target| {
|
render_on_display(None, Some(Color::black()), |target| {
|
||||||
self.render_state(self.state.index(), target);
|
self.render_state(self.state.index(), target);
|
||||||
});
|
});
|
||||||
|
84
core/embed/rust/src/ui/layout/base.rs
Normal file
84
core/embed/rust/src/ui/layout/base.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use crate::ui::{
|
||||||
|
button_request::ButtonRequest,
|
||||||
|
component::{base::AttachType, Event, EventCtx},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum LayoutState {
|
||||||
|
Initial,
|
||||||
|
Attached(Option<ButtonRequest>),
|
||||||
|
Transitioning(AttachType),
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Layout<T> {
|
||||||
|
//fn attach(&mut self, ctx: &mut EventCtx, attach_type: AttachType);
|
||||||
|
fn place(&mut self);
|
||||||
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<LayoutState>;
|
||||||
|
fn value(&self) -> Option<&T>;
|
||||||
|
fn paint(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "micropython")]
|
||||||
|
mod micropython {
|
||||||
|
use crate::micropython::{
|
||||||
|
macros::{obj_dict, obj_map, obj_type},
|
||||||
|
obj::Obj,
|
||||||
|
qstr::Qstr,
|
||||||
|
simple_type::SimpleTypeObj,
|
||||||
|
typ::Type,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::LayoutState;
|
||||||
|
|
||||||
|
static STATE_INITIAL_TYPE: Type = obj_type! {
|
||||||
|
name: Qstr::MP_QSTR_INITIAL,
|
||||||
|
base: LAYOUT_STATE_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static STATE_ATTACHED_TYPE: Type = obj_type! {
|
||||||
|
name: Qstr::MP_QSTR_ATTACHED,
|
||||||
|
base: LAYOUT_STATE_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static STATE_TRANSITIONING_TYPE: Type = obj_type! {
|
||||||
|
name: Qstr::MP_QSTR_TRANSITIONING,
|
||||||
|
base: LAYOUT_STATE_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static STATE_DONE_TYPE: Type = obj_type! {
|
||||||
|
name: Qstr::MP_QSTR_DONE,
|
||||||
|
base: LAYOUT_STATE_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static STATE_INITIAL: SimpleTypeObj = SimpleTypeObj::new(&STATE_INITIAL_TYPE);
|
||||||
|
pub static STATE_ATTACHED: SimpleTypeObj = SimpleTypeObj::new(&STATE_ATTACHED_TYPE);
|
||||||
|
pub static STATE_TRANSITIONING: SimpleTypeObj = SimpleTypeObj::new(&STATE_TRANSITIONING_TYPE);
|
||||||
|
pub static STATE_DONE: SimpleTypeObj = SimpleTypeObj::new(&STATE_DONE_TYPE);
|
||||||
|
|
||||||
|
static LAYOUT_STATE_TYPE: Type = obj_type! {
|
||||||
|
name: Qstr::MP_QSTR_LayoutState,
|
||||||
|
locals: &obj_dict! { obj_map! {
|
||||||
|
Qstr::MP_QSTR_INITIAL => STATE_INITIAL.as_obj(),
|
||||||
|
Qstr::MP_QSTR_ATTACHED => STATE_ATTACHED.as_obj(),
|
||||||
|
Qstr::MP_QSTR_TRANSITIONING => STATE_TRANSITIONING.as_obj(),
|
||||||
|
Qstr::MP_QSTR_DONE => STATE_DONE.as_obj(),
|
||||||
|
} },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static LAYOUT_STATE: SimpleTypeObj = SimpleTypeObj::new(&LAYOUT_STATE_TYPE);
|
||||||
|
|
||||||
|
impl From<LayoutState> for Obj {
|
||||||
|
fn from(state: LayoutState) -> Self {
|
||||||
|
match state {
|
||||||
|
LayoutState::Initial => STATE_INITIAL.as_obj(),
|
||||||
|
LayoutState::Attached(_) => STATE_ATTACHED.as_obj(),
|
||||||
|
LayoutState::Transitioning(_) => STATE_TRANSITIONING.as_obj(),
|
||||||
|
LayoutState::Done => STATE_DONE.as_obj(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "micropython")]
|
||||||
|
pub use micropython::*;
|
@ -1,3 +1,5 @@
|
|||||||
|
pub mod base;
|
||||||
|
|
||||||
#[cfg(feature = "micropython")]
|
#[cfg(feature = "micropython")]
|
||||||
pub mod obj;
|
pub mod obj;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use core::{
|
use core::{
|
||||||
cell::{RefCell, RefMut},
|
cell::{RefCell, RefMut},
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
|
marker::PhantomData,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
@ -8,7 +9,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
|||||||
#[cfg(feature = "button")]
|
#[cfg(feature = "button")]
|
||||||
use crate::ui::event::ButtonEvent;
|
use crate::ui::event::ButtonEvent;
|
||||||
#[cfg(feature = "new_rendering")]
|
#[cfg(feature = "new_rendering")]
|
||||||
use crate::ui::{display::Color, shape::render_on_display};
|
use crate::ui::{display::Color, shape::render_on_display, shape::Renderer};
|
||||||
#[cfg(feature = "touch")]
|
#[cfg(feature = "touch")]
|
||||||
use crate::ui::{event::TouchEvent, geometry::Direction};
|
use crate::ui::{event::TouchEvent, geometry::Direction};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -32,9 +33,13 @@ use crate::{
|
|||||||
constant, display,
|
constant, display,
|
||||||
event::USBEvent,
|
event::USBEvent,
|
||||||
geometry::Rect,
|
geometry::Rect,
|
||||||
|
ui_features::ModelUI,
|
||||||
|
UIFeaturesCommon,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::base::{Layout, LayoutState};
|
||||||
|
|
||||||
impl AttachType {
|
impl AttachType {
|
||||||
fn to_obj(self) -> Obj {
|
fn to_obj(self) -> Obj {
|
||||||
match self {
|
match self {
|
||||||
@ -89,44 +94,119 @@ pub trait ComponentMsgObj: Component {
|
|||||||
/// Note: we need to use an object-safe trait in order to store it in a `Gc<dyn
|
/// Note: we need to use an object-safe trait in order to store it in a `Gc<dyn
|
||||||
/// T>` field. `Component` itself is not object-safe because of `Component::Msg`
|
/// T>` field. `Component` itself is not object-safe because of `Component::Msg`
|
||||||
/// associated type.
|
/// associated type.
|
||||||
pub trait ObjComponent: MaybeTrace {
|
// pub trait ObjComponent: MaybeTrace {
|
||||||
fn obj_place(&mut self, bounds: Rect) -> Rect;
|
// fn obj_place(&mut self, bounds: Rect) -> Rect;
|
||||||
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,
|
||||||
fn obj_paint(&mut self);
|
// Error>; fn obj_paint(&mut self);
|
||||||
fn obj_bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
// fn obj_bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<T> ObjComponent for T
|
||||||
|
// where
|
||||||
|
// T: Component + ComponentMsgObj + MaybeTrace,
|
||||||
|
// {
|
||||||
|
// fn obj_place(&mut self, bounds: Rect) -> Rect {
|
||||||
|
// self.place(bounds)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj,
|
||||||
|
// Error> { if let Some(msg) = self.event(ctx, event) {
|
||||||
|
// self.msg_try_into_obj(msg)
|
||||||
|
// } else {
|
||||||
|
// Ok(Obj::const_none())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn obj_paint(&mut self) {
|
||||||
|
// #[cfg(not(feature = "new_rendering"))]
|
||||||
|
// {
|
||||||
|
// self.paint();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[cfg(feature = "new_rendering")]
|
||||||
|
// {
|
||||||
|
// render_on_display(None, Some(Color::black()), |target| {
|
||||||
|
// self.render(target);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
trait ComponentMaybeTrace: Component + ComponentMsgObj + MaybeTrace {}
|
||||||
|
impl<T> ComponentMaybeTrace for T where T: Component + ComponentMsgObj + MaybeTrace {}
|
||||||
|
|
||||||
|
struct RootComponent<T, M>
|
||||||
|
where
|
||||||
|
T: Component,
|
||||||
|
M: UIFeaturesCommon,
|
||||||
|
{
|
||||||
|
inner: T,
|
||||||
|
returned_value: Option<Result<Obj, Error>>,
|
||||||
|
_features: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ObjComponent for T
|
impl<T, M> RootComponent<T, M>
|
||||||
where
|
where
|
||||||
T: Component + ComponentMsgObj + MaybeTrace,
|
T: ComponentMaybeTrace,
|
||||||
|
M: UIFeaturesCommon,
|
||||||
{
|
{
|
||||||
fn obj_place(&mut self, bounds: Rect) -> Rect {
|
pub fn new(component: T) -> Self {
|
||||||
self.place(bounds)
|
Self {
|
||||||
|
inner: component,
|
||||||
|
returned_value: None,
|
||||||
|
_features: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Layout<Result<Obj, Error>> for RootComponent<T, ModelUI>
|
||||||
|
where
|
||||||
|
T: Component + ComponentMsgObj,
|
||||||
|
{
|
||||||
|
fn place(&mut self) {
|
||||||
|
self.inner.place(ModelUI::SCREEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error> {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<LayoutState> {
|
||||||
if let Some(msg) = self.event(ctx, event) {
|
if let Some(msg) = self.inner.event(ctx, event) {
|
||||||
self.msg_try_into_obj(msg)
|
self.returned_value = Some(self.inner.msg_try_into_obj(msg));
|
||||||
|
Some(LayoutState::Done)
|
||||||
|
} else if matches!(event, Event::Attach(_)) {
|
||||||
|
Some(LayoutState::Attached(ctx.button_request().take()))
|
||||||
} else {
|
} else {
|
||||||
Ok(Obj::const_none())
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_paint(&mut self) {
|
fn value(&self) -> Option<&Result<Obj, Error>> {
|
||||||
#[cfg(not(feature = "new_rendering"))]
|
self.returned_value.as_ref()
|
||||||
{
|
}
|
||||||
self.paint();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fn paint(&mut self) {
|
||||||
|
#[cfg(not(feature = "new_rendering"))]
|
||||||
|
self.inner.paint();
|
||||||
#[cfg(feature = "new_rendering")]
|
#[cfg(feature = "new_rendering")]
|
||||||
{
|
{
|
||||||
render_on_display(None, Some(Color::black()), |target| {
|
render_on_display(None, Some(Color::black()), |target| {
|
||||||
self.render(target);
|
self.inner.render(target);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ui_debug")]
|
||||||
|
impl<T> crate::trace::Trace for RootComponent<T, ModelUI>
|
||||||
|
where
|
||||||
|
T: Component + crate::trace::Trace,
|
||||||
|
{
|
||||||
|
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||||
|
self.inner.trace(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait LayoutMaybeTrace: Layout<Result<Obj, Error>> + MaybeTrace {}
|
||||||
|
impl<T> LayoutMaybeTrace for T where T: Layout<Result<Obj, Error>> + MaybeTrace {}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
|
#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))]
|
||||||
enum Repaint {
|
enum Repaint {
|
||||||
@ -145,31 +225,33 @@ pub struct LayoutObj {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct LayoutObjInner {
|
struct LayoutObjInner {
|
||||||
root: Option<GcBox<dyn ObjComponent>>,
|
root: Option<GcBox<dyn LayoutMaybeTrace>>,
|
||||||
event_ctx: EventCtx,
|
event_ctx: EventCtx,
|
||||||
timer_fn: Obj,
|
timer_fn: Obj,
|
||||||
page_count: u16,
|
page_count: u16,
|
||||||
repaint: Repaint,
|
repaint: Repaint,
|
||||||
transition_out: AttachType,
|
transition_out: AttachType,
|
||||||
|
button_request: Option<ButtonRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LayoutObjInner {
|
impl LayoutObjInner {
|
||||||
/// Create a new `LayoutObj`, wrapping a root component.
|
/// Create a new `LayoutObj`, wrapping a root component.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn new(root: impl ObjComponent + 'static) -> Result<Self, Error> {
|
pub fn new(root: impl LayoutMaybeTrace + 'static) -> Result<Self, Error> {
|
||||||
let root = GcBox::new(root)?;
|
let root = GcBox::new(root)?;
|
||||||
|
|
||||||
let mut new = Self {
|
let mut new = Self {
|
||||||
root: Some(gc::coerce!(ObjComponent, root)),
|
root: Some(gc::coerce!(LayoutMaybeTrace, root)),
|
||||||
event_ctx: EventCtx::new(),
|
event_ctx: EventCtx::new(),
|
||||||
timer_fn: Obj::const_none(),
|
timer_fn: Obj::const_none(),
|
||||||
page_count: 1,
|
page_count: 1,
|
||||||
repaint: Repaint::Full,
|
repaint: Repaint::Full,
|
||||||
transition_out: AttachType::Initial,
|
transition_out: AttachType::Initial,
|
||||||
|
button_request: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// invoke the initial placement
|
// invoke the initial placement
|
||||||
new.root_mut().obj_place(constant::screen());
|
new.root_mut().place();
|
||||||
// cause a repaint pass to update the number of pages
|
// cause a repaint pass to update the number of pages
|
||||||
let msg = new.obj_event(Event::RequestPaint);
|
let msg = new.obj_event(Event::RequestPaint);
|
||||||
assert!(matches!(msg, Ok(s) if s == Obj::const_none()));
|
assert!(matches!(msg, Ok(s) if s == Obj::const_none()));
|
||||||
@ -187,22 +269,20 @@ impl LayoutObjInner {
|
|||||||
self.timer_fn = timer_fn;
|
self.timer_fn = timer_fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root(&self) -> &impl Deref<Target = dyn ObjComponent> {
|
fn root(&self) -> &impl Deref<Target = dyn LayoutMaybeTrace> {
|
||||||
unwrap!(self.root.as_ref())
|
unwrap!(self.root.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root_mut(&mut self) -> &mut impl DerefMut<Target = dyn ObjComponent> {
|
fn root_mut(&mut self) -> &mut impl DerefMut<Target = dyn LayoutMaybeTrace> {
|
||||||
unwrap!(self.root.as_mut())
|
unwrap!(self.root.as_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn obj_request_repaint(&mut self) {
|
fn obj_request_repaint(&mut self) {
|
||||||
self.repaint = Repaint::Full;
|
self.repaint = Repaint::Full;
|
||||||
let mut event_ctx = EventCtx::new();
|
let mut event_ctx = EventCtx::new();
|
||||||
let paint_msg = self
|
let paint_msg = self.root_mut().event(&mut event_ctx, Event::RequestPaint);
|
||||||
.root_mut()
|
// paint_msg must not change the state
|
||||||
.obj_event(&mut event_ctx, Event::RequestPaint);
|
assert!(paint_msg.is_none());
|
||||||
// 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
|
// there must be no timers set
|
||||||
assert!(event_ctx.pop_timer().is_none());
|
assert!(event_ctx.pop_timer().is_none());
|
||||||
}
|
}
|
||||||
@ -217,12 +297,22 @@ impl LayoutObjInner {
|
|||||||
// Get the event context ready for a new event
|
// Get the event context ready for a new event
|
||||||
self.event_ctx.clear();
|
self.event_ctx.clear();
|
||||||
|
|
||||||
// Send the event down the component tree. Bail out in case of failure.
|
// Send the event down the component tree.
|
||||||
let msg = root.obj_event(&mut self.event_ctx, event)?;
|
let msg = root.event(&mut self.event_ctx, event);
|
||||||
|
|
||||||
|
match msg {
|
||||||
|
Some(LayoutState::Done) => return Ok(msg.into()), // short-circuit
|
||||||
|
Some(LayoutState::Attached(br)) => {
|
||||||
|
assert!(self.button_request.is_none());
|
||||||
|
self.button_request = br;
|
||||||
|
}
|
||||||
|
Some(LayoutState::Transitioning(t)) => self.transition_out = t,
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
|
||||||
// Place the root component on the screen in case it was requested.
|
// Place the root component on the screen in case it was requested.
|
||||||
if self.event_ctx.needs_place() {
|
if self.event_ctx.needs_place() {
|
||||||
root.obj_place(constant::screen());
|
root.place();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we should repaint next time
|
// Check if we should repaint next time
|
||||||
@ -251,12 +341,7 @@ impl LayoutObjInner {
|
|||||||
self.page_count = count as u16;
|
self.page_count = count as u16;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update outgoing transition if set
|
Ok(msg.into())
|
||||||
if let Some(t) = self.event_ctx.get_transition_out() {
|
|
||||||
self.transition_out = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -270,7 +355,7 @@ impl LayoutObjInner {
|
|||||||
|
|
||||||
if self.repaint != Repaint::None {
|
if self.repaint != Repaint::None {
|
||||||
self.repaint = Repaint::None;
|
self.repaint = Repaint::None;
|
||||||
self.root_mut().obj_paint();
|
self.root_mut().paint();
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -291,10 +376,10 @@ impl LayoutObjInner {
|
|||||||
// For Reasons(tm), we must pass a closure in which we call `root.trace(t)`,
|
// For Reasons(tm), we must pass a closure in which we call `root.trace(t)`,
|
||||||
// instead of passing `root` into the tracer.
|
// instead of passing `root` into the tracer.
|
||||||
|
|
||||||
// (The Reasons being, root is a `Gc<dyn ObjComponent>`, and `Gc` does not
|
// (The Reasons being, root is a `Gc<dyn LayoutMaybeTrace>`, and `Gc` does not
|
||||||
// implement `Trace`, and `dyn ObjComponent` is unsized so we can't deref it to
|
// implement `Trace`, and `dyn LayoutMaybeTrace` is unsized so we can't deref it
|
||||||
// claim that it implements `Trace`, and we also can't upcast it to `&dyn Trace`
|
// to claim that it implements `Trace`, and we also can't upcast it to
|
||||||
// because trait upcasting is unstable.
|
// `&dyn Trace` because trait upcasting is unstable.
|
||||||
// Luckily, calling `root.trace()` works perfectly fine in spite of the above.)
|
// Luckily, calling `root.trace()` works perfectly fine in spite of the above.)
|
||||||
tracer.root(&|t| {
|
tracer.root(&|t| {
|
||||||
self.root().trace(t);
|
self.root().trace(t);
|
||||||
@ -306,7 +391,7 @@ impl LayoutObjInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn obj_button_request(&mut self) -> Result<Obj, Error> {
|
fn obj_button_request(&mut self) -> Result<Obj, Error> {
|
||||||
match self.event_ctx.button_request() {
|
match self.button_request.take() {
|
||||||
None => Ok(Obj::const_none()),
|
None => Ok(Obj::const_none()),
|
||||||
Some(ButtonRequest { code, name }) => (code.num().into(), name.try_into()?).try_into(),
|
Some(ButtonRequest { code, name }) => (code.num().into(), name.try_into()?).try_into(),
|
||||||
}
|
}
|
||||||
@ -315,11 +400,23 @@ impl LayoutObjInner {
|
|||||||
fn obj_get_transition_out(&self) -> Obj {
|
fn obj_get_transition_out(&self) -> Obj {
|
||||||
self.transition_out.to_obj()
|
self.transition_out.to_obj()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn obj_return_value(&self) -> Result<Obj, Error> {
|
||||||
|
self.root()
|
||||||
|
.value()
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(Ok(Obj::const_none()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 ObjComponent + 'static) -> Result<Gc<Self>, Error> {
|
pub fn new<T: ComponentMaybeTrace + 'static>(root: T) -> Result<Gc<Self>, Error> {
|
||||||
|
let root_component = RootComponent::new(root);
|
||||||
|
Self::new_root(root_component)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_root(root: impl LayoutMaybeTrace + 'static) -> Result<Gc<Self>, Error> {
|
||||||
// SAFETY: This is a Python object and hase a base as first element
|
// SAFETY: This is a Python object and hase a base as first element
|
||||||
unsafe {
|
unsafe {
|
||||||
Gc::new_with_custom_finaliser(Self {
|
Gc::new_with_custom_finaliser(Self {
|
||||||
@ -350,6 +447,7 @@ impl LayoutObj {
|
|||||||
Qstr::MP_QSTR_page_count => obj_fn_1!(ui_layout_page_count).as_obj(),
|
Qstr::MP_QSTR_page_count => obj_fn_1!(ui_layout_page_count).as_obj(),
|
||||||
Qstr::MP_QSTR_button_request => obj_fn_1!(ui_layout_button_request).as_obj(),
|
Qstr::MP_QSTR_button_request => obj_fn_1!(ui_layout_button_request).as_obj(),
|
||||||
Qstr::MP_QSTR_get_transition_out => obj_fn_1!(ui_layout_get_transition_out).as_obj(),
|
Qstr::MP_QSTR_get_transition_out => obj_fn_1!(ui_layout_get_transition_out).as_obj(),
|
||||||
|
Qstr::MP_QSTR_return_value => obj_fn_1!(ui_layout_return_value).as_obj(),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
&TYPE
|
&TYPE
|
||||||
@ -427,9 +525,8 @@ extern "C" fn ui_layout_attach_timer_fn(this: Obj, timer_fn: Obj, attach_type: O
|
|||||||
|
|
||||||
let msg = this
|
let msg = this
|
||||||
.inner_mut()
|
.inner_mut()
|
||||||
.obj_event(Event::Attach(AttachType::try_from_obj(attach_type)?))?;
|
.obj_event(Event::Attach(AttachType::try_from_obj(attach_type)?));
|
||||||
assert!(msg == Obj::const_none());
|
msg
|
||||||
Ok(Obj::const_none())
|
|
||||||
};
|
};
|
||||||
unsafe { util::try_or_raise(block) }
|
unsafe { util::try_or_raise(block) }
|
||||||
}
|
}
|
||||||
@ -560,6 +657,15 @@ extern "C" fn ui_layout_get_transition_out(this: Obj) -> Obj {
|
|||||||
unsafe { util::try_or_raise(block) }
|
unsafe { util::try_or_raise(block) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" fn ui_layout_return_value(this: Obj) -> Obj {
|
||||||
|
let block = || {
|
||||||
|
let this: Gc<LayoutObj> = this.try_into()?;
|
||||||
|
let value = this.inner_mut().obj_return_value();
|
||||||
|
value
|
||||||
|
};
|
||||||
|
unsafe { util::try_or_raise(block) }
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[cfg(feature = "ui_debug")]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn ui_debug_layout_type() -> &'static Type {
|
pub extern "C" fn ui_debug_layout_type() -> &'static Type {
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
use crate::micropython::{macros::obj_type, qstr::Qstr, simple_type::SimpleTypeObj, typ::Type};
|
use crate::micropython::{
|
||||||
|
macros::{obj_dict, obj_map, obj_type},
|
||||||
|
qstr::Qstr,
|
||||||
|
simple_type::SimpleTypeObj,
|
||||||
|
typ::Type,
|
||||||
|
};
|
||||||
|
|
||||||
static CONFIRMED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CONFIRMED, };
|
static CONFIRMED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CONFIRMED, };
|
||||||
static CANCELLED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CANCELLED, };
|
static CANCELLED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CANCELLED, };
|
||||||
|
@ -13,7 +13,6 @@ pub enum BinarySelectionMsg {
|
|||||||
|
|
||||||
/// Component presenting a binary choice represented as two buttons, left and
|
/// Component presenting a binary choice represented as two buttons, left and
|
||||||
/// right. Both buttons are parameterized with content and style.
|
/// right. Both buttons are parameterized with content and style.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct BinarySelection {
|
pub struct BinarySelection {
|
||||||
buttons_area: Rect,
|
buttons_area: Rect,
|
||||||
button_left: Button,
|
button_left: Button,
|
||||||
|
@ -271,7 +271,7 @@ fn new_confirm_action_uni<T: Component + MaybeTrace + 'static>(
|
|||||||
|
|
||||||
let flow = create_confirm(flow, strings.subtitle, hold, prompt_screen)?;
|
let flow = create_confirm(flow, strings.subtitle, hold, prompt_screen)?;
|
||||||
|
|
||||||
Ok(LayoutObj::new(flow)?.into())
|
Ok(LayoutObj::new_root(flow)?.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_flow(
|
fn create_flow(
|
||||||
|
@ -214,6 +214,6 @@ impl ConfirmFido {
|
|||||||
.with_page(&ConfirmFido::Details, content_details)?
|
.with_page(&ConfirmFido::Details, content_details)?
|
||||||
.with_page(&ConfirmFido::Tap, content_tap)?
|
.with_page(&ConfirmFido::Tap, content_tap)?
|
||||||
.with_page(&ConfirmFido::Menu, content_menu)?;
|
.with_page(&ConfirmFido::Menu, content_menu)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,6 +137,6 @@ impl ConfirmFirmwareUpdate {
|
|||||||
.with_page(&ConfirmFirmwareUpdate::Menu, content_menu)?
|
.with_page(&ConfirmFirmwareUpdate::Menu, content_menu)?
|
||||||
.with_page(&ConfirmFirmwareUpdate::Fingerprint, content_fingerprint)?
|
.with_page(&ConfirmFirmwareUpdate::Fingerprint, content_fingerprint)?
|
||||||
.with_page(&ConfirmFirmwareUpdate::Confirm, content_confirm)?;
|
.with_page(&ConfirmFirmwareUpdate::Confirm, content_confirm)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,5 +450,5 @@ fn new_confirm_output_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Err
|
|||||||
.with_page(&ConfirmOutput::CancelTap, get_cancel_page())?
|
.with_page(&ConfirmOutput::CancelTap, get_cancel_page())?
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
|
@ -166,5 +166,5 @@ fn new_confirm_reset_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Erro
|
|||||||
.with_page(&ConfirmResetCreate::Menu, content_menu)?
|
.with_page(&ConfirmResetCreate::Menu, content_menu)?
|
||||||
.with_page(&ConfirmResetCreate::Confirm, content_confirm)?
|
.with_page(&ConfirmResetCreate::Confirm, content_confirm)?
|
||||||
};
|
};
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,6 @@ impl SetNewPin {
|
|||||||
.with_page(&SetNewPin::Menu, content_menu)?
|
.with_page(&SetNewPin::Menu, content_menu)?
|
||||||
.with_page(&SetNewPin::CancelPinIntro, content_cancel_intro)?
|
.with_page(&SetNewPin::CancelPinIntro, content_cancel_intro)?
|
||||||
.with_page(&SetNewPin::CancelPinConfirm, content_cancel_confirm)?;
|
.with_page(&SetNewPin::CancelPinConfirm, content_cancel_confirm)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,6 +203,6 @@ impl ConfirmSummary {
|
|||||||
.with_page(&ConfirmSummary::AccountInfo, content_account)?
|
.with_page(&ConfirmSummary::AccountInfo, content_account)?
|
||||||
.with_page(&ConfirmSummary::CancelTap, content_cancel_tap)?;
|
.with_page(&ConfirmSummary::CancelTap, content_cancel_tap)?;
|
||||||
|
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,5 +360,5 @@ fn new_obj(_args: &[Obj], kwargs: &Map) -> Result<Obj, error::Error> {
|
|||||||
content_remaining_shares,
|
content_remaining_shares,
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
|
@ -233,6 +233,6 @@ impl GetAddress {
|
|||||||
.with_page(&GetAddress::AccountInfo, content_account)?
|
.with_page(&GetAddress::AccountInfo, content_account)?
|
||||||
.with_page(&GetAddress::Cancel, content_cancel_info)?
|
.with_page(&GetAddress::Cancel, content_cancel_info)?
|
||||||
.with_page(&GetAddress::CancelTap, content_cancel_tap)?;
|
.with_page(&GetAddress::CancelTap, content_cancel_tap)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,6 @@ impl PromptBackup {
|
|||||||
.with_page(&PromptBackup::Menu, content_menu)?
|
.with_page(&PromptBackup::Menu, content_menu)?
|
||||||
.with_page(&PromptBackup::SkipBackupIntro, content_skip_intro)?
|
.with_page(&PromptBackup::SkipBackupIntro, content_skip_intro)?
|
||||||
.with_page(&PromptBackup::SkipBackupConfirm, content_skip_confirm)?;
|
.with_page(&PromptBackup::SkipBackupConfirm, content_skip_confirm)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,6 @@ impl RequestNumber {
|
|||||||
.with_page(&RequestNumber::Number, content_number_input)?
|
.with_page(&RequestNumber::Number, content_number_input)?
|
||||||
.with_page(&RequestNumber::Menu, content_menu)?
|
.with_page(&RequestNumber::Menu, content_menu)?
|
||||||
.with_page(&RequestNumber::Info, content_info)?;
|
.with_page(&RequestNumber::Info, content_info)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,6 @@ impl RequestPassphrase {
|
|||||||
let res = SwipeFlow::new(&RequestPassphrase::Keypad)?
|
let res = SwipeFlow::new(&RequestPassphrase::Keypad)?
|
||||||
.with_page(&RequestPassphrase::Keypad, content_keypad)?
|
.with_page(&RequestPassphrase::Keypad, content_keypad)?
|
||||||
.with_page(&RequestPassphrase::ConfirmEmpty, content_confirm_empty)?;
|
.with_page(&RequestPassphrase::ConfirmEmpty, content_confirm_empty)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,6 @@ impl SetBrightness {
|
|||||||
.with_page(&SetBrightness::Confirm, content_confirm)?
|
.with_page(&SetBrightness::Confirm, content_confirm)?
|
||||||
.with_page(&SetBrightness::Confirmed, content_confirmed)?;
|
.with_page(&SetBrightness::Confirmed, content_confirmed)?;
|
||||||
|
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,6 +160,6 @@ impl ShowShareWords {
|
|||||||
&ShowShareWords::CheckBackupIntro,
|
&ShowShareWords::CheckBackupIntro,
|
||||||
content_check_backup_intro,
|
content_check_backup_intro,
|
||||||
)?;
|
)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,6 @@ impl ShowTutorial {
|
|||||||
.with_page(&ShowTutorial::Menu, content_menu)?
|
.with_page(&ShowTutorial::Menu, content_menu)?
|
||||||
.with_page(&ShowTutorial::DidYouKnow, content_did_you_know)?
|
.with_page(&ShowTutorial::DidYouKnow, content_did_you_know)?
|
||||||
.with_page(&ShowTutorial::HoldToExit, content_hold_to_exit)?;
|
.with_page(&ShowTutorial::HoldToExit, content_hold_to_exit)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,6 @@ impl WarningHiPrio {
|
|||||||
.with_page(&WarningHiPrio::Message, content_message)?
|
.with_page(&WarningHiPrio::Message, content_message)?
|
||||||
.with_page(&WarningHiPrio::Menu, content_menu)?
|
.with_page(&WarningHiPrio::Menu, content_menu)?
|
||||||
.with_page(&WarningHiPrio::Cancelled, content_cancelled)?;
|
.with_page(&WarningHiPrio::Cancelled, content_cancelled)?;
|
||||||
Ok(LayoutObj::new(res)?.into())
|
Ok(LayoutObj::new_root(res)?.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,9 +44,7 @@ use crate::{
|
|||||||
flow::Swipable,
|
flow::Swipable,
|
||||||
geometry::{self, Direction},
|
geometry::{self, Direction},
|
||||||
layout::{
|
layout::{
|
||||||
obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ},
|
base::LAYOUT_STATE, obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ}, result::{CANCELLED, CONFIRMED, INFO}, util::{upy_disable_animation, ConfirmBlob, PropsList, RecoveryType}
|
||||||
result::{CANCELLED, CONFIRMED, INFO},
|
|
||||||
util::{upy_disable_animation, ConfirmBlob, PropsList, RecoveryType},
|
|
||||||
},
|
},
|
||||||
model_mercury::{
|
model_mercury::{
|
||||||
component::{check_homescreen_format, SwipeContent},
|
component::{check_homescreen_format, SwipeContent},
|
||||||
@ -883,7 +881,7 @@ extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mu
|
|||||||
|
|
||||||
let flow =
|
let flow =
|
||||||
confirm_with_info::new_confirm_with_info(title, button, info_button, paragraphs)?;
|
confirm_with_info::new_confirm_with_info(title, button, info_button, paragraphs)?;
|
||||||
Ok(LayoutObj::new(flow)?.into())
|
Ok(LayoutObj::new_root(flow)?.into())
|
||||||
};
|
};
|
||||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||||
}
|
}
|
||||||
@ -1206,82 +1204,6 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub static mp_module_trezorui2: Module = obj_module! {
|
pub static mp_module_trezorui2: Module = obj_module! {
|
||||||
/// from trezor import utils
|
/// from trezor import utils
|
||||||
///
|
|
||||||
/// T = TypeVar("T")
|
|
||||||
///
|
|
||||||
/// class LayoutObj(Generic[T]):
|
|
||||||
/// """Representation of a Rust-based layout object.
|
|
||||||
/// see `trezor::ui::layout::obj::LayoutObj`.
|
|
||||||
/// """
|
|
||||||
///
|
|
||||||
/// def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> None:
|
|
||||||
/// """Attach a timer setter function.
|
|
||||||
///
|
|
||||||
/// The layout object can call the timer setter with two arguments,
|
|
||||||
/// `token` and `duration_ms`. When `duration_ms` is reached, the layout object
|
|
||||||
/// expects a callback to `self.timer(token)`.
|
|
||||||
/// """
|
|
||||||
///
|
|
||||||
/// if utils.USE_TOUCH:
|
|
||||||
/// def touch_event(self, event: int, x: int, y: int) -> T | None:
|
|
||||||
/// """Receive a touch event `event` at coordinates `x`, `y`."""
|
|
||||||
///
|
|
||||||
/// if utils.USE_BUTTON:
|
|
||||||
/// def button_event(self, event: int, button: int) -> T | None:
|
|
||||||
/// """Receive a button event `event` for button `button`."""
|
|
||||||
///
|
|
||||||
/// def progress_event(self, value: int, description: str) -> T | None:
|
|
||||||
/// """Receive a progress event."""
|
|
||||||
///
|
|
||||||
/// def usb_event(self, connected: bool) -> T | None:
|
|
||||||
/// """Receive a USB connect/disconnect event."""
|
|
||||||
///
|
|
||||||
/// def timer(self, token: int) -> T | None:
|
|
||||||
/// """Callback for the timer set by `attach_timer_fn`.
|
|
||||||
///
|
|
||||||
/// This function should be called by the executor after the corresponding
|
|
||||||
/// duration has expired.
|
|
||||||
/// """
|
|
||||||
///
|
|
||||||
/// def paint(self) -> bool:
|
|
||||||
/// """Paint the layout object on screen.
|
|
||||||
///
|
|
||||||
/// Will only paint updated parts of the layout as required.
|
|
||||||
/// Returns True if any painting actually happened.
|
|
||||||
/// """
|
|
||||||
///
|
|
||||||
/// def request_complete_repaint(self) -> None:
|
|
||||||
/// """Request a complete repaint of the screen.
|
|
||||||
///
|
|
||||||
/// Does not repaint the screen, a subsequent call to `paint()` is required.
|
|
||||||
/// """
|
|
||||||
///
|
|
||||||
/// if __debug__:
|
|
||||||
/// def trace(self, tracer: Callable[[str], None]) -> None:
|
|
||||||
/// """Generate a JSON trace of the layout object.
|
|
||||||
///
|
|
||||||
/// The JSON can be emitted as a sequence of calls to `tracer`, each of
|
|
||||||
/// which is not necessarily a valid JSON chunk. The caller must
|
|
||||||
/// reassemble the chunks to get a sensible result.
|
|
||||||
/// """
|
|
||||||
///
|
|
||||||
/// def bounds(self) -> None:
|
|
||||||
/// """Paint bounds of individual components on screen."""
|
|
||||||
///
|
|
||||||
/// def page_count(self) -> int:
|
|
||||||
/// """Return the number of pages in the layout object."""
|
|
||||||
///
|
|
||||||
/// def get_transition_out(self) -> AttachType:
|
|
||||||
/// """Return the transition type."""
|
|
||||||
///
|
|
||||||
/// def __del__(self) -> None:
|
|
||||||
/// """Calls drop on contents of the root component."""
|
|
||||||
///
|
|
||||||
/// class UiResult:
|
|
||||||
/// """Result of a UI operation."""
|
|
||||||
/// pass
|
|
||||||
///
|
|
||||||
/// mock:global
|
|
||||||
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(),
|
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorui2.to_obj(),
|
||||||
|
|
||||||
/// CONFIRMED: UiResult
|
/// CONFIRMED: UiResult
|
||||||
@ -1818,4 +1740,11 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// SWIPE_RIGHT: ClassVar[int]
|
/// SWIPE_RIGHT: ClassVar[int]
|
||||||
Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(),
|
Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(),
|
||||||
|
|
||||||
|
/// class LayoutState:
|
||||||
|
/// """Layout state."""
|
||||||
|
/// INITIAL: "ClassVar[LayoutState]"
|
||||||
|
/// ATTACHED: "ClassVar[LayoutState]"
|
||||||
|
/// TRANSITIONING: "ClassVar[LayoutState]"
|
||||||
|
/// DONE: "ClassVar[LayoutState]"
|
||||||
|
Qstr::MP_QSTR_LayoutState => LAYOUT_STATE.as_obj(),
|
||||||
};
|
};
|
||||||
|
@ -47,9 +47,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
geometry,
|
geometry,
|
||||||
layout::{
|
layout::{
|
||||||
obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ},
|
base::LAYOUT_STATE, obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ}, result::{CANCELLED, CONFIRMED, INFO}, util::{upy_disable_animation, ConfirmBlob, RecoveryType}
|
||||||
result::{CANCELLED, CONFIRMED, INFO},
|
|
||||||
util::{upy_disable_animation, ConfirmBlob, RecoveryType},
|
|
||||||
},
|
},
|
||||||
model_tr::component::check_homescreen_format,
|
model_tr::component::check_homescreen_format,
|
||||||
},
|
},
|
||||||
@ -2144,4 +2142,12 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// SWIPE_LEFT: ClassVar[int]
|
/// SWIPE_LEFT: ClassVar[int]
|
||||||
/// SWIPE_RIGHT: ClassVar[int]
|
/// SWIPE_RIGHT: ClassVar[int]
|
||||||
Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(),
|
Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(),
|
||||||
|
|
||||||
|
/// class LayoutState:
|
||||||
|
/// """Layout state."""
|
||||||
|
/// INITIAL: "ClassVar[LayoutState]"
|
||||||
|
/// ATTACHED: "ClassVar[LayoutState]"
|
||||||
|
/// TRANSITIONING: "ClassVar[LayoutState]"
|
||||||
|
/// DONE: "ClassVar[LayoutState]"
|
||||||
|
Qstr::MP_QSTR_LayoutState => LAYOUT_STATE.as_obj(),
|
||||||
};
|
};
|
||||||
|
@ -50,9 +50,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
geometry,
|
geometry,
|
||||||
layout::{
|
layout::{
|
||||||
obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ},
|
base::LAYOUT_STATE, obj::{ComponentMsgObj, LayoutObj, ATTACH_TYPE_OBJ}, result::{CANCELLED, CONFIRMED, INFO}, util::{upy_disable_animation, ConfirmBlob, PropsList, RecoveryType}
|
||||||
result::{CANCELLED, CONFIRMED, INFO},
|
|
||||||
util::{upy_disable_animation, ConfirmBlob, PropsList, RecoveryType},
|
|
||||||
},
|
},
|
||||||
model_tt::component::check_homescreen_format,
|
model_tt::component::check_homescreen_format,
|
||||||
},
|
},
|
||||||
@ -1660,7 +1658,7 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// see `trezor::ui::layout::obj::LayoutObj`.
|
/// see `trezor::ui::layout::obj::LayoutObj`.
|
||||||
/// """
|
/// """
|
||||||
///
|
///
|
||||||
/// def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> None:
|
/// def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> LayoutState | None:
|
||||||
/// """Attach a timer setter function.
|
/// """Attach a timer setter function.
|
||||||
///
|
///
|
||||||
/// The layout object can call the timer setter with two arguments,
|
/// The layout object can call the timer setter with two arguments,
|
||||||
@ -1669,20 +1667,20 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// """
|
/// """
|
||||||
///
|
///
|
||||||
/// if utils.USE_TOUCH:
|
/// if utils.USE_TOUCH:
|
||||||
/// def touch_event(self, event: int, x: int, y: int) -> T | None:
|
/// def touch_event(self, event: int, x: int, y: int) -> LayoutState | None:
|
||||||
/// """Receive a touch event `event` at coordinates `x`, `y`."""
|
/// """Receive a touch event `event` at coordinates `x`, `y`."""
|
||||||
///
|
///
|
||||||
/// if utils.USE_BUTTON:
|
/// if utils.USE_BUTTON:
|
||||||
/// def button_event(self, event: int, button: int) -> T | None:
|
/// def button_event(self, event: int, button: int) -> LayoutState | None:
|
||||||
/// """Receive a button event `event` for button `button`."""
|
/// """Receive a button event `event` for button `button`."""
|
||||||
///
|
///
|
||||||
/// def progress_event(self, value: int, description: str) -> T | None:
|
/// def progress_event(self, value: int, description: str) -> LayoutState | None:
|
||||||
/// """Receive a progress event."""
|
/// """Receive a progress event."""
|
||||||
///
|
///
|
||||||
/// def usb_event(self, connected: bool) -> T | None:
|
/// def usb_event(self, connected: bool) -> LayoutState | None:
|
||||||
/// """Receive a USB connect/disconnect event."""
|
/// """Receive a USB connect/disconnect event."""
|
||||||
///
|
///
|
||||||
/// def timer(self, token: int) -> T | None:
|
/// def timer(self, token: int) -> LayoutState | None:
|
||||||
/// """Callback for the timer set by `attach_timer_fn`.
|
/// """Callback for the timer set by `attach_timer_fn`.
|
||||||
///
|
///
|
||||||
/// This function should be called by the executor after the corresponding
|
/// This function should be called by the executor after the corresponding
|
||||||
@ -1722,6 +1720,9 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
///
|
///
|
||||||
/// def get_transition_out(self) -> AttachType:
|
/// def get_transition_out(self) -> AttachType:
|
||||||
/// """Return the transition type."""
|
/// """Return the transition type."""
|
||||||
|
///
|
||||||
|
/// def return_value(self) -> T:
|
||||||
|
/// """Retrieve the return value of the layout object."""
|
||||||
///
|
///
|
||||||
/// def __del__(self) -> None:
|
/// def __del__(self) -> None:
|
||||||
/// """Calls drop on contents of the root component."""
|
/// """Calls drop on contents of the root component."""
|
||||||
@ -2199,6 +2200,14 @@ pub static mp_module_trezorui2: Module = obj_module! {
|
|||||||
/// SWIPE_LEFT: ClassVar[int]
|
/// SWIPE_LEFT: ClassVar[int]
|
||||||
/// SWIPE_RIGHT: ClassVar[int]
|
/// SWIPE_RIGHT: ClassVar[int]
|
||||||
Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(),
|
Qstr::MP_QSTR_AttachType => ATTACH_TYPE_OBJ.as_obj(),
|
||||||
|
|
||||||
|
/// class LayoutState:
|
||||||
|
/// """Layout state."""
|
||||||
|
/// INITIAL: "ClassVar[LayoutState]"
|
||||||
|
/// ATTACHED: "ClassVar[LayoutState]"
|
||||||
|
/// TRANSITIONING: "ClassVar[LayoutState]"
|
||||||
|
/// DONE: "ClassVar[LayoutState]"
|
||||||
|
Qstr::MP_QSTR_LayoutState => LAYOUT_STATE.as_obj(),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,64 +1,5 @@
|
|||||||
from typing import *
|
from typing import *
|
||||||
from trezor import utils
|
from trezor import utils
|
||||||
T = TypeVar("T")
|
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_mercury/layout.rs
|
|
||||||
class LayoutObj(Generic[T]):
|
|
||||||
"""Representation of a Rust-based layout object.
|
|
||||||
see `trezor::ui::layout::obj::LayoutObj`.
|
|
||||||
"""
|
|
||||||
def attach_timer_fn(self, fn: Callable[[int, int], None], attach_type: AttachType | None) -> None:
|
|
||||||
"""Attach a timer setter function.
|
|
||||||
The layout object can call the timer setter with two arguments,
|
|
||||||
`token` and `duration_ms`. When `duration_ms` is reached, the layout object
|
|
||||||
expects a callback to `self.timer(token)`.
|
|
||||||
"""
|
|
||||||
if utils.USE_TOUCH:
|
|
||||||
def touch_event(self, event: int, x: int, y: int) -> T | None:
|
|
||||||
"""Receive a touch event `event` at coordinates `x`, `y`."""
|
|
||||||
if utils.USE_BUTTON:
|
|
||||||
def button_event(self, event: int, button: int) -> T | None:
|
|
||||||
"""Receive a button event `event` for button `button`."""
|
|
||||||
def progress_event(self, value: int, description: str) -> T | None:
|
|
||||||
"""Receive a progress event."""
|
|
||||||
def usb_event(self, connected: bool) -> T | None:
|
|
||||||
"""Receive a USB connect/disconnect event."""
|
|
||||||
def timer(self, token: int) -> T | None:
|
|
||||||
"""Callback for the timer set by `attach_timer_fn`.
|
|
||||||
This function should be called by the executor after the corresponding
|
|
||||||
duration has expired.
|
|
||||||
"""
|
|
||||||
def paint(self) -> bool:
|
|
||||||
"""Paint the layout object on screen.
|
|
||||||
Will only paint updated parts of the layout as required.
|
|
||||||
Returns True if any painting actually happened.
|
|
||||||
"""
|
|
||||||
def request_complete_repaint(self) -> None:
|
|
||||||
"""Request a complete repaint of the screen.
|
|
||||||
Does not repaint the screen, a subsequent call to `paint()` is required.
|
|
||||||
"""
|
|
||||||
if __debug__:
|
|
||||||
def trace(self, tracer: Callable[[str], None]) -> None:
|
|
||||||
"""Generate a JSON trace of the layout object.
|
|
||||||
The JSON can be emitted as a sequence of calls to `tracer`, each of
|
|
||||||
which is not necessarily a valid JSON chunk. The caller must
|
|
||||||
reassemble the chunks to get a sensible result.
|
|
||||||
"""
|
|
||||||
def bounds(self) -> None:
|
|
||||||
"""Paint bounds of individual components on screen."""
|
|
||||||
def page_count(self) -> int:
|
|
||||||
"""Return the number of pages in the layout object."""
|
|
||||||
def get_transition_out(self) -> AttachType:
|
|
||||||
"""Return the transition type."""
|
|
||||||
def __del__(self) -> None:
|
|
||||||
"""Calls drop on contents of the root component."""
|
|
||||||
|
|
||||||
|
|
||||||
# rust/src/ui/model_mercury/layout.rs
|
|
||||||
class UiResult:
|
|
||||||
"""Result of a UI operation."""
|
|
||||||
pass
|
|
||||||
CONFIRMED: UiResult
|
CONFIRMED: UiResult
|
||||||
CANCELLED: UiResult
|
CANCELLED: UiResult
|
||||||
INFO: UiResult
|
INFO: UiResult
|
||||||
@ -634,6 +575,15 @@ class AttachType:
|
|||||||
SWIPE_DOWN: ClassVar[int]
|
SWIPE_DOWN: ClassVar[int]
|
||||||
SWIPE_LEFT: ClassVar[int]
|
SWIPE_LEFT: ClassVar[int]
|
||||||
SWIPE_RIGHT: ClassVar[int]
|
SWIPE_RIGHT: ClassVar[int]
|
||||||
|
|
||||||
|
|
||||||
|
# rust/src/ui/model_mercury/layout.rs
|
||||||
|
class LayoutState:
|
||||||
|
"""Layout state."""
|
||||||
|
INITIAL: "ClassVar[LayoutState]"
|
||||||
|
ATTACHED: "ClassVar[LayoutState]"
|
||||||
|
TRANSITIONING: "ClassVar[LayoutState]"
|
||||||
|
DONE: "ClassVar[LayoutState]"
|
||||||
CONFIRMED: UiResult
|
CONFIRMED: UiResult
|
||||||
CANCELLED: UiResult
|
CANCELLED: UiResult
|
||||||
INFO: UiResult
|
INFO: UiResult
|
||||||
@ -1123,6 +1073,15 @@ class AttachType:
|
|||||||
SWIPE_DOWN: ClassVar[int]
|
SWIPE_DOWN: ClassVar[int]
|
||||||
SWIPE_LEFT: ClassVar[int]
|
SWIPE_LEFT: ClassVar[int]
|
||||||
SWIPE_RIGHT: ClassVar[int]
|
SWIPE_RIGHT: ClassVar[int]
|
||||||
|
|
||||||
|
|
||||||
|
# rust/src/ui/model_tr/layout.rs
|
||||||
|
class LayoutState:
|
||||||
|
"""Layout state."""
|
||||||
|
INITIAL: "ClassVar[LayoutState]"
|
||||||
|
ATTACHED: "ClassVar[LayoutState]"
|
||||||
|
TRANSITIONING: "ClassVar[LayoutState]"
|
||||||
|
DONE: "ClassVar[LayoutState]"
|
||||||
from trezor import utils
|
from trezor import utils
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
@ -1139,16 +1098,16 @@ class LayoutObj(Generic[T]):
|
|||||||
expects a callback to `self.timer(token)`.
|
expects a callback to `self.timer(token)`.
|
||||||
"""
|
"""
|
||||||
if utils.USE_TOUCH:
|
if utils.USE_TOUCH:
|
||||||
def touch_event(self, event: int, x: int, y: int) -> T | None:
|
def touch_event(self, event: int, x: int, y: int) -> LayoutState | None:
|
||||||
"""Receive a touch event `event` at coordinates `x`, `y`."""
|
"""Receive a touch event `event` at coordinates `x`, `y`."""
|
||||||
if utils.USE_BUTTON:
|
if utils.USE_BUTTON:
|
||||||
def button_event(self, event: int, button: int) -> T | None:
|
def button_event(self, event: int, button: int) -> LayoutState | None:
|
||||||
"""Receive a button event `event` for button `button`."""
|
"""Receive a button event `event` for button `button`."""
|
||||||
def progress_event(self, value: int, description: str) -> T | None:
|
def progress_event(self, value: int, description: str) -> LayoutState | None:
|
||||||
"""Receive a progress event."""
|
"""Receive a progress event."""
|
||||||
def usb_event(self, connected: bool) -> T | None:
|
def usb_event(self, connected: bool) -> LayoutState | None:
|
||||||
"""Receive a USB connect/disconnect event."""
|
"""Receive a USB connect/disconnect event."""
|
||||||
def timer(self, token: int) -> T | None:
|
def timer(self, token: int) -> LayoutState | None:
|
||||||
"""Callback for the timer set by `attach_timer_fn`.
|
"""Callback for the timer set by `attach_timer_fn`.
|
||||||
This function should be called by the executor after the corresponding
|
This function should be called by the executor after the corresponding
|
||||||
duration elapses.
|
duration elapses.
|
||||||
@ -1177,6 +1136,9 @@ class LayoutObj(Generic[T]):
|
|||||||
"""Return (code, type) of button request made during the last event or timer pass."""
|
"""Return (code, type) of button request made during the last event or timer pass."""
|
||||||
def get_transition_out(self) -> AttachType:
|
def get_transition_out(self) -> AttachType:
|
||||||
"""Return the transition type."""
|
"""Return the transition type."""
|
||||||
|
|
||||||
|
def return_value(self) -> T:
|
||||||
|
"""Retrieve the return value of the layout object."""
|
||||||
def __del__(self) -> None:
|
def __del__(self) -> None:
|
||||||
"""Calls drop on contents of the root component."""
|
"""Calls drop on contents of the root component."""
|
||||||
|
|
||||||
@ -1689,3 +1651,12 @@ class AttachType:
|
|||||||
SWIPE_DOWN: ClassVar[int]
|
SWIPE_DOWN: ClassVar[int]
|
||||||
SWIPE_LEFT: ClassVar[int]
|
SWIPE_LEFT: ClassVar[int]
|
||||||
SWIPE_RIGHT: ClassVar[int]
|
SWIPE_RIGHT: ClassVar[int]
|
||||||
|
|
||||||
|
|
||||||
|
# rust/src/ui/model_tt/layout.rs
|
||||||
|
class LayoutState:
|
||||||
|
"""Layout state."""
|
||||||
|
INITIAL: "ClassVar[LayoutState]"
|
||||||
|
ATTACHED: "ClassVar[LayoutState]"
|
||||||
|
TRANSITIONING: "ClassVar[LayoutState]"
|
||||||
|
DONE: "ClassVar[LayoutState]"
|
||||||
|
Loading…
Reference in New Issue
Block a user