Skip to content

Commit

Permalink
DROP feat(core/ui): sending button requests from rust
Browse files Browse the repository at this point in the history
this is supposed to go into main via #3714
  • Loading branch information
mmilata committed May 20, 2024
1 parent 3c05d03 commit e8cf782
Show file tree
Hide file tree
Showing 16 changed files with 361 additions and 104 deletions.
1 change: 1 addition & 0 deletions core/embed/rust/librust_qstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ static void _librust_qstrs(void) {
MP_QSTR_bounds;
MP_QSTR_button;
MP_QSTR_button_event;
MP_QSTR_button_request;
MP_QSTR_buttons__abort;
MP_QSTR_buttons__access;
MP_QSTR_buttons__again;
Expand Down
60 changes: 60 additions & 0 deletions core/embed/rust/src/ui/button_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::strutil::TString;
use num_traits::FromPrimitive;

// ButtonRequestType from messages-common.proto
// Eventually this should be generated
#[derive(Clone, Copy, FromPrimitive)]
#[repr(u16)]
pub enum ButtonRequestCode {
Other = 1,
FeeOverThreshold = 2,
ConfirmOutput = 3,
ResetDevice = 4,
ConfirmWord = 5,
WipeDevice = 6,
ProtectCall = 7,
SignTx = 8,
FirmwareCheck = 9,
Address = 10,
PublicKey = 11,
MnemonicWordCount = 12,
MnemonicInput = 13,
UnknownDerivationPath = 15,
RecoveryHomepage = 16,
Success = 17,
Warning = 18,
PassphraseEntry = 19,
PinEntry = 20,
}

impl ButtonRequestCode {
pub fn num(&self) -> u16 {
*self as u16
}

pub fn with_type(self, br_type: &'static str) -> ButtonRequest {
ButtonRequest::new(self, br_type.into())
}

pub fn from(i: u16) -> Self {
unwrap!(Self::from_u16(i))
}
}

const MAX_TYPE_LEN: usize = 32;

#[derive(Clone)]
pub struct ButtonRequest {
pub code: ButtonRequestCode,
pub br_type: TString<'static>,
}

impl ButtonRequest {
pub fn new(code: ButtonRequestCode, br_type: TString<'static>) -> Self {
ButtonRequest { code, br_type }
}

pub fn from_tstring(code: u16, br_type: TString<'static>) -> Self {
ButtonRequest::new(ButtonRequestCode::from(code), br_type)
}
}
16 changes: 16 additions & 0 deletions core/embed/rust/src/ui/component/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
strutil::TString,
time::Duration,
ui::{
button_request::{ButtonRequest, ButtonRequestCode},
component::{maybe::PaintOverlapping, MsgMap},
display::{self, Color},
geometry::{Offset, Rect},
Expand Down Expand Up @@ -487,6 +488,7 @@ pub struct EventCtx {
paint_requested: bool,
anim_frame_scheduled: bool,
page_count: Option<usize>,
button_request: Option<ButtonRequest>,
root_repaint_requested: bool,
}

Expand All @@ -513,6 +515,7 @@ impl EventCtx {
* `Child::marked_for_paint` being true. */
anim_frame_scheduled: false,
page_count: None,
button_request: None,
root_repaint_requested: false,
}
}
Expand Down Expand Up @@ -570,6 +573,16 @@ impl EventCtx {
self.page_count
}

pub fn send_button_request(&mut self, code: ButtonRequestCode, br_type: TString<'static>) {
#[cfg(feature = "ui_debug")]
assert!(self.button_request.is_none());
self.button_request = Some(ButtonRequest::new(code, br_type));
}

pub fn button_request(&mut self) -> Option<ButtonRequest> {
self.button_request.take()
}

pub fn pop_timer(&mut self) -> Option<(TimerToken, Duration)> {
self.timers.pop()
}
Expand All @@ -579,6 +592,9 @@ impl EventCtx {
self.paint_requested = false;
self.anim_frame_scheduled = false;
self.page_count = None;
#[cfg(feature = "ui_debug")]
assert!(self.button_request.is_none());
self.button_request = None;
self.root_repaint_requested = false;
}

Expand Down
65 changes: 65 additions & 0 deletions core/embed/rust/src/ui/component/button_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use crate::ui::{
button_request::ButtonRequest,
component::{Component, Event, EventCtx},
geometry::Rect,
};

/// Component that sends a ButtonRequest after receiving Event::Attach. The
/// request is only sent once.
#[derive(Clone)]
pub struct OneButtonRequest<T> {
button_request: Option<ButtonRequest>,
pub inner: T,
}

impl<T> OneButtonRequest<T> {
pub fn new(button_request: ButtonRequest, inner: T) -> Self {
Self {
button_request: Some(button_request),
inner,
}
}
}

impl<T: Component> Component for OneButtonRequest<T> {
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> {
if matches!(event, Event::Attach) {
if let Some(button_request) = self.button_request.take() {
ctx.send_button_request(button_request.code, button_request.br_type)
}
}
self.inner.event(ctx, event)
}

fn paint(&mut self) {
self.inner.paint()
}

fn render<'s>(&'s self, target: &mut impl crate::ui::shape::Renderer<'s>) {
self.inner.render(target)
}
}

#[cfg(feature = "ui_debug")]
impl<T: crate::trace::Trace> crate::trace::Trace for OneButtonRequest<T> {
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
self.inner.trace(t)
}
}

pub trait ButtonRequestExt {
fn one_button_request(self, br: ButtonRequest) -> OneButtonRequest<Self>
where
Self: Sized,
{
OneButtonRequest::new(br, self)
}
}

impl<T: Component> ButtonRequestExt for T {}
2 changes: 2 additions & 0 deletions core/embed/rust/src/ui/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod bar;
pub mod base;
pub mod border;
pub mod button_request;
pub mod connect;
pub mod empty;
pub mod image;
Expand All @@ -24,6 +25,7 @@ pub mod timeout;
pub use bar::Bar;
pub use base::{Child, Component, ComponentExt, Event, EventCtx, Never, Root, TimerToken};
pub use border::Border;
pub use button_request::{ButtonRequestExt, OneButtonRequest};
pub use empty::Empty;
#[cfg(all(feature = "jpeg", feature = "micropython"))]
pub use jpeg::Jpeg;
Expand Down
21 changes: 21 additions & 0 deletions core/embed/rust/src/ui/layout/obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::{
},
time::Duration,
ui::{
button_request::ButtonRequest,
component::{Component, Event, EventCtx, Never, Root, TimerToken},
constant,
display::sync,
Expand Down Expand Up @@ -248,6 +249,17 @@ impl LayoutObj {
self.inner.borrow().page_count.into()
}

fn obj_button_request(&self) -> Result<Obj, Error> {
let inner = &mut *self.inner.borrow_mut();

match inner.event_ctx.button_request() {
None => Ok(Obj::const_none()),
Some(ButtonRequest { code, br_type }) => {
(code.num().into(), br_type.try_into()?).try_into()
}
}
}

#[cfg(feature = "ui_debug")]
fn obj_bounds(&self) {
use crate::ui::display;
Expand Down Expand Up @@ -280,6 +292,7 @@ impl LayoutObj {
Qstr::MP_QSTR_trace => obj_fn_2!(ui_layout_trace).as_obj(),
Qstr::MP_QSTR_bounds => obj_fn_1!(ui_layout_bounds).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(),
}),
};
&TYPE
Expand Down Expand Up @@ -470,6 +483,14 @@ extern "C" fn ui_layout_page_count(this: Obj) -> Obj {
unsafe { util::try_or_raise(block) }
}

extern "C" fn ui_layout_button_request(this: Obj) -> Obj {
let block = || {
let this: Gc<LayoutObj> = this.try_into()?;
this.obj_button_request()
};
unsafe { util::try_or_raise(block) }
}

#[cfg(feature = "ui_debug")]
#[no_mangle]
pub extern "C" fn ui_debug_layout_type() -> &'static Type {
Expand Down
1 change: 1 addition & 0 deletions core/embed/rust/src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pub mod macros;

pub mod animation;
pub mod button_request;
pub mod component;
pub mod constant;
pub mod display;
Expand Down
3 changes: 3 additions & 0 deletions core/embed/rust/src/ui/model_tt/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,9 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// def page_count(self) -> int:
/// """Return the number of pages in the layout object."""
///
/// def button_request(self) -> tuple[int, str] | None:
/// """Return (code, type) of button request made during the last event or timer pass."""
///
/// class UiResult:
/// """Result of a UI operation."""
/// pass
Expand Down
2 changes: 2 additions & 0 deletions core/mocks/generated/trezorui2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,8 @@ class LayoutObj(Generic[T]):
"""Paint bounds of individual components on screen."""
def page_count(self) -> int:
"""Return the number of pages in the layout object."""
def button_request(self) -> tuple[int, str] | None:
"""Return (code, type) of button request made during the last event or timer pass."""


# rust/src/ui/model_tt/layout.rs
Expand Down
2 changes: 1 addition & 1 deletion core/src/trezor/ui/layouts/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ async def interact(
# We know for certain how many pages the layout will have
pages = layout.page_count() # type: ignore [Cannot access attribute "page_count" for class "LayoutType"]
await button_request(br_type, br_code, pages)
return await context.wait(layout)
return await layout
Loading

0 comments on commit e8cf782

Please sign in to comment.