mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-05 17:56:10 +00:00
chore(core/rust): Simplify LayoutObj
This commit is contained in:
parent
2b6f1a4d5c
commit
4c027a688c
@ -43,12 +43,32 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// In order to store any type of component in a layout, we need to access it
|
||||
/// through an object-safe trait. `Component` itself is not object-safe because
|
||||
/// of `Component::Msg` associated type. `ObjComponent` is a simple object-safe
|
||||
/// wrapping trait that is implemented for all components where `Component::Msg`
|
||||
/// can be converted to `Obj` through the `ComponentMsgObj` trait.
|
||||
pub trait ObjComponent {
|
||||
#[cfg(feature = "ui_debug")]
|
||||
mod maybe_trace {
|
||||
pub trait MaybeTrace: crate::trace::Trace {}
|
||||
impl<T> MaybeTrace for T where T: crate::trace::Trace {}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ui_debug"))]
|
||||
mod maybe_trace {
|
||||
pub trait MaybeTrace {}
|
||||
impl<T> MaybeTrace for T {}
|
||||
}
|
||||
|
||||
/// Stand-in for the optionally-compiled trait `Trace`.
|
||||
/// If UI debugging is enabled, `MaybeTrace` implies `Trace` and is implemented
|
||||
/// for everything that implements Trace. If disabled, `MaybeTrace` is
|
||||
/// implemented for everything.
|
||||
use maybe_trace::MaybeTrace;
|
||||
|
||||
/// Object-safe interface between trait `Component` and MicroPython world. It
|
||||
/// converts the result of `Component::event` into `Obj` via the
|
||||
/// `ComponentMsgObj` trait, in order to easily return the value to Python. It
|
||||
/// also optionally implies `Trace` for UI debugging.
|
||||
/// 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`
|
||||
/// associated type.
|
||||
pub trait ObjComponent: MaybeTrace {
|
||||
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error>;
|
||||
fn obj_paint(&mut self);
|
||||
fn obj_bounds(&self, sink: &mut dyn FnMut(Rect));
|
||||
@ -56,7 +76,7 @@ pub trait ObjComponent {
|
||||
|
||||
impl<T> ObjComponent for Child<T>
|
||||
where
|
||||
T: ComponentMsgObj,
|
||||
T: ComponentMsgObj + MaybeTrace,
|
||||
{
|
||||
fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result<Obj, Error> {
|
||||
if let Some(msg) = self.event(ctx, event) {
|
||||
@ -75,22 +95,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
mod maybe_trace {
|
||||
pub trait ObjComponentTrace: super::ObjComponent + crate::trace::Trace {}
|
||||
impl<T> ObjComponentTrace for T where T: super::ObjComponent + crate::trace::Trace {}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ui_debug"))]
|
||||
mod maybe_trace {
|
||||
pub trait ObjComponentTrace: super::ObjComponent {}
|
||||
impl<T> ObjComponentTrace for T where T: super::ObjComponent {}
|
||||
}
|
||||
|
||||
/// Trait that combines `ObjComponent` with `Trace` if `ui_debug` is enabled,
|
||||
/// and pure `ObjComponent` otherwise.
|
||||
use maybe_trace::ObjComponentTrace;
|
||||
|
||||
/// `LayoutObj` is a GC-allocated object exported to MicroPython, with type
|
||||
/// `LayoutObj::obj_type()`. It wraps a root component through the
|
||||
/// `ObjComponent` trait.
|
||||
@ -101,17 +105,20 @@ pub struct LayoutObj {
|
||||
}
|
||||
|
||||
struct LayoutObjInner {
|
||||
root: Gc<dyn ObjComponentTrace>,
|
||||
root: Gc<dyn ObjComponent>,
|
||||
event_ctx: EventCtx,
|
||||
timer_fn: Obj,
|
||||
}
|
||||
|
||||
impl LayoutObj {
|
||||
/// Create a new `LayoutObj`, wrapping a root component.
|
||||
pub fn new(root: impl ObjComponentTrace + '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
|
||||
// invalidation logic.
|
||||
let wrapped_root = Child::new(root);
|
||||
// SAFETY: We are coercing GC-allocated sized ptr into an unsized one.
|
||||
let root =
|
||||
unsafe { Gc::from_raw(Gc::into_raw(Gc::new(root)?) as *mut dyn ObjComponentTrace) };
|
||||
unsafe { Gc::from_raw(Gc::into_raw(Gc::new(wrapped_root)?) as *mut dyn ObjComponent) };
|
||||
|
||||
Gc::new(Self {
|
||||
base: Self::obj_type().as_base(),
|
||||
|
@ -3,7 +3,7 @@ use core::convert::TryInto;
|
||||
use crate::{
|
||||
micropython::{buffer::Buffer, map::Map, obj::Obj, qstr::Qstr},
|
||||
ui::{
|
||||
component::{text::paragraphs::Paragraphs, Child, FormattedText},
|
||||
component::{text::paragraphs::Paragraphs, FormattedText},
|
||||
display,
|
||||
layout::obj::LayoutObj,
|
||||
},
|
||||
@ -44,7 +44,7 @@ extern "C" fn ui_layout_new_confirm_action(
|
||||
let right = verb
|
||||
.map(|label| |area, pos| Button::with_text(area, pos, label, theme::button_default()));
|
||||
|
||||
let obj = LayoutObj::new(Child::new(Frame::new(display::screen(), title, |area| {
|
||||
let obj = LayoutObj::new(Frame::new(display::screen(), title, |area| {
|
||||
ButtonPage::new(
|
||||
area,
|
||||
|area| {
|
||||
@ -54,7 +54,7 @@ extern "C" fn ui_layout_new_confirm_action(
|
||||
},
|
||||
theme::BG,
|
||||
)
|
||||
})))?;
|
||||
}))?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
@ -72,7 +72,7 @@ extern "C" fn ui_layout_new_confirm_text(
|
||||
let description: Option<Buffer> =
|
||||
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
||||
|
||||
let obj = LayoutObj::new(Child::new(Frame::new(display::screen(), title, |area| {
|
||||
let obj = LayoutObj::new(Frame::new(display::screen(), title, |area| {
|
||||
ButtonPage::new(
|
||||
area,
|
||||
|area| {
|
||||
@ -85,7 +85,7 @@ extern "C" fn ui_layout_new_confirm_text(
|
||||
},
|
||||
theme::BG,
|
||||
)
|
||||
})))?;
|
||||
}))?;
|
||||
Ok(obj.into())
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
|
||||
@ -125,7 +125,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn trace_example_layout() {
|
||||
let layout = Child::new(Dialog::new(
|
||||
let layout = Dialog::new(
|
||||
display::screen(),
|
||||
|area| {
|
||||
FormattedText::new::<theme::T1DefaultText>(
|
||||
@ -136,7 +136,7 @@ mod tests {
|
||||
},
|
||||
Some(|area, pos| Button::with_text(area, pos, "Left", theme::button_cancel())),
|
||||
Some(|area, pos| Button::with_text(area, pos, "Right", theme::button_default())),
|
||||
));
|
||||
);
|
||||
assert_eq!(
|
||||
trace(&layout),
|
||||
r#"<Dialog content:<Text content:Testing text layout,
|
||||
@ -148,7 +148,7 @@ arameters! > left:<Button text:Left > right:<Button text:Right > >"#
|
||||
|
||||
#[test]
|
||||
fn trace_layout_title() {
|
||||
let layout = Child::new(Frame::new(display::screen(), "Please confirm", |area| {
|
||||
let layout = Frame::new(display::screen(), "Please confirm", |area| {
|
||||
Dialog::new(
|
||||
area,
|
||||
|area| {
|
||||
@ -161,7 +161,7 @@ arameters! > left:<Button text:Left > right:<Button text:Right > >"#
|
||||
Some(|area, pos| Button::with_text(area, pos, "Left", theme::button_cancel())),
|
||||
Some(|area, pos| Button::with_text(area, pos, "Right", theme::button_default())),
|
||||
)
|
||||
}));
|
||||
});
|
||||
assert_eq!(
|
||||
trace(&layout),
|
||||
r#"<Frame title:Please confirm content:<Dialog content:<Text content:Testing text layout,
|
||||
|
@ -52,13 +52,13 @@ where
|
||||
#[no_mangle]
|
||||
extern "C" fn ui_layout_new_example(_param: Obj) -> Obj {
|
||||
let block = move || {
|
||||
let layout = LayoutObj::new(Child::new(HoldToConfirm::new(display::screen(), |area| {
|
||||
let layout = LayoutObj::new(HoldToConfirm::new(display::screen(), |area| {
|
||||
FormattedText::new::<theme::TTDefaultText>(
|
||||
area,
|
||||
"Testing text layout, with some text, and some more text. And {param}",
|
||||
)
|
||||
.with(b"param", b"parameters!")
|
||||
})))?;
|
||||
}))?;
|
||||
Ok(layout.into())
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
|
Loading…
Reference in New Issue
Block a user