mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-23 23:08:14 +00:00
refactor(core/rust/ui): arbitrary controls for Dialog component
[no changelog]
This commit is contained in:
parent
62ab48d2e6
commit
9f0ebf6d1a
@ -210,6 +210,39 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Component for Option<T>
|
||||
where
|
||||
T: Component,
|
||||
{
|
||||
type Msg = T::Msg;
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
match self {
|
||||
Some(ref mut c) => c.event(ctx, event),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
if let Some(ref mut c) = self {
|
||||
c.paint()
|
||||
}
|
||||
}
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
match self {
|
||||
Some(ref mut c) => c.place(bounds),
|
||||
_ => bounds.with_size(Offset::zero()),
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
if let Some(ref c) = self {
|
||||
c.bounds(sink)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ComponentExt: Sized {
|
||||
fn map<F>(self, func: F) -> Map<Self, F>;
|
||||
fn into_child(self) -> Child<Self>;
|
||||
|
@ -52,8 +52,9 @@ where
|
||||
let layout = DialogLayout::middle(bounds);
|
||||
self.loader.place(layout.content);
|
||||
self.content.place(layout.content);
|
||||
self.cancel.place(layout.left);
|
||||
self.confirm.place(layout.right);
|
||||
let (left, right) = layout.controls.split_left(layout.controls.size().x);
|
||||
self.cancel.place(left);
|
||||
self.confirm.place(right);
|
||||
bounds
|
||||
}
|
||||
|
||||
|
@ -3,29 +3,27 @@ use crate::ui::{
|
||||
geometry::{Grid, Rect},
|
||||
};
|
||||
|
||||
pub enum DialogMsg<T, L, R> {
|
||||
use super::{theme, Button};
|
||||
|
||||
pub enum DialogMsg<T, U> {
|
||||
Content(T),
|
||||
Left(L),
|
||||
Right(R),
|
||||
Controls(U),
|
||||
}
|
||||
|
||||
pub struct Dialog<T, L, R> {
|
||||
pub struct Dialog<T, U> {
|
||||
content: Child<T>,
|
||||
left: Child<L>,
|
||||
right: Child<R>,
|
||||
controls: Child<U>,
|
||||
}
|
||||
|
||||
impl<T, L, R> Dialog<T, L, R>
|
||||
impl<T, U> Dialog<T, U>
|
||||
where
|
||||
T: Component,
|
||||
L: Component,
|
||||
R: Component,
|
||||
U: Component,
|
||||
{
|
||||
pub fn new(content: T, left: L, right: R) -> Self {
|
||||
pub fn new(content: T, controls: U) -> Self {
|
||||
Self {
|
||||
content: Child::new(content),
|
||||
left: Child::new(left),
|
||||
right: Child::new(right),
|
||||
controls: Child::new(controls),
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,19 +32,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, L, R> Component for Dialog<T, L, R>
|
||||
impl<T, U> Component for Dialog<T, U>
|
||||
where
|
||||
T: Component,
|
||||
L: Component,
|
||||
R: Component,
|
||||
U: Component,
|
||||
{
|
||||
type Msg = DialogMsg<T::Msg, L::Msg, R::Msg>;
|
||||
type Msg = DialogMsg<T::Msg, U::Msg>;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
let layout = DialogLayout::middle(bounds);
|
||||
self.content.place(layout.content);
|
||||
self.left.place(layout.left);
|
||||
self.right.place(layout.right);
|
||||
self.controls.place(layout.controls);
|
||||
bounds
|
||||
}
|
||||
|
||||
@ -54,55 +50,48 @@ where
|
||||
self.content
|
||||
.event(ctx, event)
|
||||
.map(Self::Msg::Content)
|
||||
.or_else(|| self.left.event(ctx, event).map(Self::Msg::Left))
|
||||
.or_else(|| self.right.event(ctx, event).map(Self::Msg::Right))
|
||||
.or_else(|| self.controls.event(ctx, event).map(Self::Msg::Controls))
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.content.paint();
|
||||
self.left.paint();
|
||||
self.right.paint();
|
||||
self.controls.paint();
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.content.bounds(sink);
|
||||
self.left.bounds(sink);
|
||||
self.right.bounds(sink);
|
||||
self.controls.bounds(sink);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DialogLayout {
|
||||
pub content: Rect,
|
||||
pub left: Rect,
|
||||
pub right: Rect,
|
||||
pub controls: Rect,
|
||||
}
|
||||
|
||||
impl DialogLayout {
|
||||
pub fn middle(area: Rect) -> Self {
|
||||
let grid = Grid::new(area, 5, 2);
|
||||
let grid = Grid::new(area, 5, 1);
|
||||
Self {
|
||||
content: Rect::new(
|
||||
grid.row_col(0, 0).top_left(),
|
||||
grid.row_col(3, 1).bottom_right(),
|
||||
grid.row_col(3, 0).bottom_right(),
|
||||
),
|
||||
left: grid.row_col(4, 0),
|
||||
right: grid.row_col(4, 1),
|
||||
controls: grid.row_col(4, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<T, L, R> crate::trace::Trace for Dialog<T, L, R>
|
||||
impl<T, U> crate::trace::Trace for Dialog<T, U>
|
||||
where
|
||||
T: crate::trace::Trace,
|
||||
L: crate::trace::Trace,
|
||||
R: crate::trace::Trace,
|
||||
U: crate::trace::Trace,
|
||||
{
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.open("Dialog");
|
||||
t.field("content", &self.content);
|
||||
t.field("left", &self.left);
|
||||
t.field("right", &self.right);
|
||||
t.field("controls", &self.controls);
|
||||
t.close();
|
||||
}
|
||||
}
|
||||
|
@ -26,17 +26,16 @@ use super::{
|
||||
theme,
|
||||
};
|
||||
|
||||
impl<T, U> ComponentMsgObj for Dialog<T, Button<U>, Button<U>>
|
||||
impl<T, U> ComponentMsgObj for Dialog<T, U>
|
||||
where
|
||||
T: ComponentMsgObj,
|
||||
U: AsRef<str>,
|
||||
U: Component<Msg = bool>,
|
||||
{
|
||||
fn msg_try_into_obj(&self, msg: Self::Msg) -> Result<Obj, Error> {
|
||||
match msg {
|
||||
DialogMsg::Content(c) => Ok(self.inner().msg_try_into_obj(c)?),
|
||||
DialogMsg::Left(ButtonMsg::Clicked) => Ok(CANCELLED.as_obj()),
|
||||
DialogMsg::Right(ButtonMsg::Clicked) => Ok(CONFIRMED.as_obj()),
|
||||
_ => Ok(Obj::const_none()),
|
||||
DialogMsg::Controls(false) => Ok(CANCELLED.as_obj()),
|
||||
DialogMsg::Controls(true) => Ok(CONFIRMED.as_obj()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -283,18 +282,23 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn trace_example_layout() {
|
||||
let buttons = Button::left_right(
|
||||
Button::with_text("Left"),
|
||||
|msg| (matches!(msg, ButtonMsg::Clicked)).then(|| false),
|
||||
Button::with_text("Right"),
|
||||
|msg| (matches!(msg, ButtonMsg::Clicked)).then(|| true),
|
||||
);
|
||||
let mut layout = Dialog::new(
|
||||
FormattedText::new::<theme::TTDefaultText>(
|
||||
"Testing text layout, with some text, and some more text. And {param}",
|
||||
)
|
||||
.with("param", "parameters!"),
|
||||
Button::with_text("Left"),
|
||||
Button::with_text("Right"),
|
||||
buttons,
|
||||
);
|
||||
layout.place(SCREEN);
|
||||
assert_eq!(
|
||||
trace(&layout),
|
||||
"<Dialog content:<Text content:Testing text layout, with\nsome text, and some more\ntext. And parameters! > left:<Button text:Left > right:<Button text:Right > >",
|
||||
"<Dialog content:<Text content:Testing text layout, with\nsome text, and some more\ntext. And parameters! > controls:<Tuple 0:<GridPlaced inner:<Button text:Left > > 1:<GridPlaced inner:<Button text:Right > > > >",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user