From afe965687fce224ab9457c6d8e1b4cb3cb80f478 Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Mon, 13 Mar 2023 23:09:51 +0100 Subject: [PATCH] fix(core/ui): style update: frame and corner button [no changelog] --- .../ui/model_tt/component/address_details.rs | 15 +- .../rust/src/ui/model_tt/component/button.rs | 90 +--------- .../rust/src/ui/model_tt/component/frame.rs | 80 ++++++++- .../rust/src/ui/model_tt/component/mod.rs | 4 +- core/embed/rust/src/ui/model_tt/layout.rs | 165 +++++++----------- core/embed/rust/src/ui/model_tt/theme.rs | 12 +- 6 files changed, 153 insertions(+), 213 deletions(-) diff --git a/core/embed/rust/src/ui/model_tt/component/address_details.rs b/core/embed/rust/src/ui/model_tt/component/address_details.rs index 1140063603..0c3f6a760d 100644 --- a/core/embed/rust/src/ui/model_tt/component/address_details.rs +++ b/core/embed/rust/src/ui/model_tt/component/address_details.rs @@ -7,13 +7,13 @@ use crate::{ text::paragraphs::{ Paragraph, ParagraphSource, ParagraphStrType, ParagraphVecShort, Paragraphs, VecExt, }, - Component, Event, EventCtx, Never, Paginate, Qr, + Component, Event, EventCtx, Paginate, Qr, }, geometry::Rect, }, }; -use super::{theme, Frame}; +use super::{theme, Frame, FrameMsg}; const MAX_XPUBS: usize = 16; @@ -57,18 +57,21 @@ where "RECEIVE ADDRESS".into(), Qr::new(qr_address, case_sensitive)?.with_border(7), ) + .with_cancel_button() .with_border(theme::borders_horizontal_scroll()), details: Frame::left_aligned( theme::label_title(), "RECEIVING TO".into(), para.into_paragraphs(), ) + .with_cancel_button() .with_border(theme::borders_horizontal_scroll()), xpub_view: Frame::left_aligned( theme::label_title(), " \n ".into(), Paragraph::new(&theme::TEXT_MONO, "".into()).into_paragraphs(), ) + .with_cancel_button() .with_border(theme::borders_horizontal_scroll()), xpubs: Vec::new(), xpub_page_count: Vec::new(), @@ -142,7 +145,7 @@ impl Component for AddressDetails where T: ParagraphStrType + Clone, { - type Msg = Never; + type Msg = (); fn place(&mut self, bounds: Rect) -> Rect { self.qr_code.place(bounds); @@ -159,10 +162,14 @@ where } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - match self.current_page { + let msg = match self.current_page { 0 => self.qr_code.event(ctx, event), 1 => self.details.event(ctx, event), _ => self.xpub_view.event(ctx, event), + }; + match msg { + Some(FrameMsg::Button(_)) => Some(()), + _ => None, } } diff --git a/core/embed/rust/src/ui/model_tt/component/button.rs b/core/embed/rust/src/ui/model_tt/component/button.rs index 1917688b10..ad9df23922 100644 --- a/core/embed/rust/src/ui/model_tt/component/button.rs +++ b/core/embed/rust/src/ui/model_tt/component/button.rs @@ -2,8 +2,7 @@ use crate::{ time::Duration, ui::{ component::{ - Component, ComponentExt, Event, EventCtx, FixedHeightBar, Floating, Map, Paginate, - Split, TimerToken, + Component, ComponentExt, Event, EventCtx, FixedHeightBar, Map, Split, TimerToken, }, display::{self, toif::Icon, Color, Font}, event::TouchEvent, @@ -514,6 +513,7 @@ type CancelInfoConfirm = type CancelConfirm = FixedHeightBar, F0>, Map, F1>>>; +#[derive(Clone, Copy)] pub enum CancelInfoConfirmMsg { Cancelled, Info, @@ -582,89 +582,3 @@ impl IconText { } } } - -pub struct FloatingButton { - inner: T, - button: Floating>, -} - -pub enum FloatingButtonMsg { - ButtonClicked, - Content(T), -} - -impl FloatingButton -where - T: Component, -{ - pub const fn top_right_corner(icon: Icon, inner: T) -> Self { - Self { - inner, - button: Floating::top_right( - theme::CORNER_BUTTON_SIDE, - theme::CORNER_BUTTON_SPACING, - Button::with_icon(icon) - .with_expanded_touch_area(Insets::uniform(theme::CORNER_BUTTON_SPACING)) - .styled(theme::button_moreinfo()), - ), - } - } - - pub fn inner(&self) -> &T { - &self.inner - } -} - -impl Component for FloatingButton -where - T: Component, -{ - type Msg = FloatingButtonMsg; - - fn place(&mut self, bounds: Rect) -> Rect { - self.button.place(bounds); - self.inner.place(bounds) - } - - fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - if let Some(ButtonMsg::Clicked) = self.button.event(ctx, event) { - return Some(FloatingButtonMsg::ButtonClicked); - } - self.inner.event(ctx, event).map(FloatingButtonMsg::Content) - } - - fn paint(&mut self) { - self.inner.paint(); - self.button.paint(); - } - - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.inner.bounds(sink); - self.button.bounds(sink); - } -} - -impl Paginate for FloatingButton -where - T: Paginate, -{ - fn page_count(&mut self) -> usize { - self.inner.page_count() - } - - fn change_page(&mut self, to_page: usize) { - self.inner.change_page(to_page) - } -} - -#[cfg(feature = "ui_debug")] -impl crate::trace::Trace for FloatingButton -where - T: Component + crate::trace::Trace, -{ - fn trace(&self, t: &mut dyn crate::trace::Tracer) { - t.open("FloatingButton"); - t.field("inner", self.inner()); - t.close(); - } -} diff --git a/core/embed/rust/src/ui/model_tt/component/frame.rs b/core/embed/rust/src/ui/model_tt/component/frame.rs index 7fc67cb17d..43ffeab873 100644 --- a/core/embed/rust/src/ui/model_tt/component/frame.rs +++ b/core/embed/rust/src/ui/model_tt/component/frame.rs @@ -3,16 +3,24 @@ use crate::ui::{ component::{ base::ComponentExt, label::Label, text::TextStyle, Child, Component, Event, EventCtx, }, - display::{self, Color, Font}, + display::{self, Color, Font, Icon}, geometry::{Alignment, Insets, Offset, Rect}, + model_tt::component::{Button, ButtonMsg, CancelInfoConfirmMsg}, }; pub struct Frame { border: Insets, title: Child>, + button: Option>>, + button_msg: CancelInfoConfirmMsg, content: Child, } +pub enum FrameMsg { + Content(T), + Button(CancelInfoConfirmMsg), +} + impl Frame where T: Component, @@ -21,7 +29,9 @@ where pub fn new(style: TextStyle, alignment: Alignment, title: U, content: T) -> Self { Self { title: Child::new(Label::new(title, alignment, style)), - border: theme::borders_scroll(), + border: theme::borders(), + button: None, + button_msg: CancelInfoConfirmMsg::Cancelled, content: Child::new(content), } } @@ -43,6 +53,35 @@ where self } + fn with_button(mut self, icon: Icon, msg: CancelInfoConfirmMsg) -> Self { + let touch_area = Insets { + left: self.border.left * 4, + bottom: self.border.bottom * 4, + ..self.border + }; + self.button = Some(Child::new( + Button::with_icon(icon) + .with_expanded_touch_area(touch_area) + .styled(theme::button_moreinfo()), + )); + self.button_msg = msg; + self + } + + pub fn with_cancel_button(self) -> Self { + self.with_button( + Icon::new(theme::ICON_CORNER_CANCEL), + CancelInfoConfirmMsg::Cancelled, + ) + } + + pub fn with_info_button(self) -> Self { + self.with_button( + Icon::new(theme::ICON_CORNER_INFO), + CancelInfoConfirmMsg::Info, + ) + } + pub fn inner(&self) -> &T { self.content.inner() } @@ -71,31 +110,51 @@ where T: Component, U: AsRef, { - type Msg = T::Msg; + type Msg = FrameMsg; fn place(&mut self, bounds: Rect) -> Rect { const TITLE_SPACE: i16 = theme::BUTTON_SPACING; let bounds = bounds.inset(self.border); - let title_area = bounds.inset(Insets::sides(theme::CONTENT_BORDER)); - let title_area = self.title.place(title_area); - let content_area = bounds.inset(Insets::top(title_area.height() + TITLE_SPACE)); - self.content.place(content_area); + if let Some(b) = &mut self.button { + let button_side = theme::CORNER_BUTTON_SIDE; + let (title_area, button_area) = bounds.split_right(button_side); + let (button_area, _) = button_area.split_top(button_side); + b.place(button_area); + let title_area = self.title.place(title_area); + let title_height = title_area.height(); + let height = title_area.height().max(button_side); + if title_height < button_side { + self.title + .place(title_area.translate(Offset::y((button_side - title_height) / 2))); + } + let content_area = bounds.inset(Insets::top(height + TITLE_SPACE)); + self.content.place(content_area); + } else { + let title_area = self.title.place(bounds); + let content_area = bounds.inset(Insets::top(title_area.height() + TITLE_SPACE)); + self.content.place(content_area); + } bounds } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { self.title.event(ctx, event); - self.content.event(ctx, event) + if let Some(ButtonMsg::Clicked) = self.button.event(ctx, event) { + return Some(FrameMsg::Button(self.button_msg)); + } + self.content.event(ctx, event).map(FrameMsg::Content) } fn paint(&mut self) { self.title.paint(); + self.button.paint(); self.content.paint(); } fn bounds(&self, sink: &mut dyn FnMut(Rect)) { self.title.bounds(sink); + self.button.bounds(sink); self.content.bounds(sink); } } @@ -109,6 +168,9 @@ where fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.open("Frame"); t.field("title", &self.title); + if let Some(b) = &self.button { + t.field("button", b); + } t.field("content", &self.content); t.close(); } @@ -150,7 +212,7 @@ where display::text_center( area.center() + Offset::y((font.text_max_height() - font.text_baseline()) / 2), title, - Font::BOLD, + font, theme::FG, color, ); diff --git a/core/embed/rust/src/ui/model_tt/component/mod.rs b/core/embed/rust/src/ui/model_tt/component/mod.rs index bcf3f12ece..095e407c83 100644 --- a/core/embed/rust/src/ui/model_tt/component/mod.rs +++ b/core/embed/rust/src/ui/model_tt/component/mod.rs @@ -22,11 +22,11 @@ mod welcome_screen; pub use address_details::AddressDetails; pub use button::{ Button, ButtonContent, ButtonMsg, ButtonStyle, ButtonStyleSheet, CancelConfirmMsg, - CancelInfoConfirmMsg, FloatingButton, FloatingButtonMsg, IconText, SelectWordMsg, + CancelInfoConfirmMsg, IconText, SelectWordMsg, }; pub use dialog::{Dialog, DialogMsg, IconDialog}; pub use fido::{FidoConfirm, FidoMsg}; -pub use frame::{Frame, NotificationFrame}; +pub use frame::{Frame, FrameMsg, NotificationFrame}; pub use hold_to_confirm::{HoldToConfirm, HoldToConfirmMsg}; #[cfg(feature = "dma2d")] pub use homescreen::{Homescreen, HomescreenMsg, Lockscreen}; diff --git a/core/embed/rust/src/ui/model_tt/layout.rs b/core/embed/rust/src/ui/model_tt/layout.rs index ab775aca96..2726072a92 100644 --- a/core/embed/rust/src/ui/model_tt/layout.rs +++ b/core/embed/rust/src/ui/model_tt/layout.rs @@ -46,13 +46,12 @@ use crate::{ use super::{ component::{ AddressDetails, Bip39Input, Button, ButtonMsg, ButtonStyleSheet, CancelConfirmMsg, - CancelInfoConfirmMsg, Dialog, DialogMsg, FidoConfirm, FidoMsg, FloatingButton, - FloatingButtonMsg, Frame, HoldToConfirm, HoldToConfirmMsg, Homescreen, HomescreenMsg, - HorizontalPage, IconDialog, Lockscreen, MnemonicInput, MnemonicKeyboard, - MnemonicKeyboardMsg, NotificationFrame, NumberInputDialog, NumberInputDialogMsg, - PassphraseKeyboard, PassphraseKeyboardMsg, PinKeyboard, PinKeyboardMsg, Progress, - SelectWordCount, SelectWordCountMsg, SelectWordMsg, Slip39Input, SwipeHoldPage, SwipePage, - WelcomeScreen, + CancelInfoConfirmMsg, Dialog, DialogMsg, FidoConfirm, FidoMsg, Frame, FrameMsg, + HoldToConfirm, HoldToConfirmMsg, Homescreen, HomescreenMsg, HorizontalPage, IconDialog, + Lockscreen, MnemonicInput, MnemonicKeyboard, MnemonicKeyboardMsg, NotificationFrame, + NumberInputDialog, NumberInputDialogMsg, PassphraseKeyboard, PassphraseKeyboardMsg, + PinKeyboard, PinKeyboardMsg, Progress, SelectWordCount, SelectWordCountMsg, SelectWordMsg, + Slip39Input, SwipeHoldPage, SwipePage, WelcomeScreen, }, constant, theme, }; @@ -200,7 +199,10 @@ where U: AsRef, { fn msg_try_into_obj(&self, msg: Self::Msg) -> Result { - self.inner().msg_try_into_obj(msg) + match msg { + FrameMsg::Content(c) => self.inner().msg_try_into_obj(c), + FrameMsg::Button(b) => b.try_into(), + } } } @@ -340,18 +342,6 @@ impl ComponentMsgObj for Qr { } } -impl ComponentMsgObj for FloatingButton -where - T: ComponentMsgObj, -{ - fn msg_try_into_obj(&self, msg: Self::Msg) -> Result { - match msg { - FloatingButtonMsg::ButtonClicked => Ok(INFO.as_obj()), - FloatingButtonMsg::Content(c) => self.inner().msg_try_into_obj(c), - } - } -} - impl ComponentMsgObj for HorizontalPage where T: ComponentMsgObj + Paginate, @@ -371,7 +361,7 @@ where T: ParagraphStrType + Clone, { fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result { - unreachable!(); + Ok(CANCELLED.as_obj()) } } @@ -508,16 +498,16 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut .into_paragraphs(); let buttons = Button::cancel_confirm_text(None, Some("CONFIRM")); - let obj = LayoutObj::new(FloatingButton::top_right_corner( - Icon::new(theme::ICON_CORNER_INFO), + let obj = LayoutObj::new( Frame::left_aligned( theme::label_title(), title, SwipePage::new(paragraphs, buttons, theme::BG) .with_swipe_left() .with_cancel_on_first_page(), - ), - ))?; + ) + .with_info_button(), + )?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -572,14 +562,11 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m }; let buttons = Button::cancel_confirm_text(None, Some("CONFIRM")); - let obj = LayoutObj::new( - Frame::centered( - theme::label_title(), - title, - Dialog::new(painter::jpeg_painter(buffer_func, size, 1), buttons), - ) - .with_border(theme::borders()), - )?; + let obj = LayoutObj::new(Frame::centered( + theme::label_title(), + title, + Dialog::new(painter::jpeg_painter(buffer_func, size, 1), buttons), + ))?; Ok(obj.into()) }; @@ -606,14 +593,11 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs: Button::with_text(button).styled(theme::button_confirm()), true, ); - let obj = LayoutObj::new( - Frame::left_aligned( - theme::label_title(), - title, - Dialog::new(paragraphs, buttons), - ) - .with_border(theme::borders()), - )?; + let obj = LayoutObj::new(Frame::left_aligned( + theme::label_title(), + title, + Dialog::new(paragraphs, buttons), + ))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -632,14 +616,11 @@ extern "C" fn new_show_qr(n_args: usize, args: *const Obj, kwargs: *mut Map) -> false, ); - let obj = LayoutObj::new( - Frame::left_aligned( - theme::label_title(), - title, - Dialog::new(Qr::new(address, case_sensitive)?.with_border(4), buttons), - ) - .with_border(theme::borders()), - )?; + let obj = LayoutObj::new(Frame::left_aligned( + theme::label_title(), + title, + Dialog::new(Qr::new(address, case_sensitive)?.with_border(4), buttons), + ))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -663,13 +644,7 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs: ad.add_xpub(xtitle, text)?; } - let obj = LayoutObj::new( - HorizontalPage::new( - FloatingButton::top_right_corner(Icon::new(theme::ICON_CORNER_CANCEL), ad), - theme::BG, - ) - .with_swipe_right_to_go_back(), - )?; + let obj = LayoutObj::new(HorizontalPage::new(ad, theme::BG).with_swipe_right_to_go_back())?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -889,9 +864,7 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map let fido_page = FidoConfirm::new(app_name, get_page, page_count, icon, controls); - let obj = LayoutObj::new( - Frame::centered(theme::label_title(), title, fido_page).with_border(theme::borders()), - )?; + let obj = LayoutObj::new(Frame::centered(theme::label_title(), title, fido_page))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -1043,14 +1016,11 @@ extern "C" fn new_confirm_with_info(n_args: usize, args: *const Obj, kwargs: *mu let buttons = Button::cancel_info_confirm(button, info_button); - let obj = LayoutObj::new( - Frame::left_aligned( - theme::label_title(), - title, - Dialog::new(paragraphs.into_paragraphs(), buttons), - ) - .with_border(theme::borders()), - )?; + let obj = LayoutObj::new(Frame::left_aligned( + theme::label_title(), + title, + Dialog::new(paragraphs.into_paragraphs(), buttons), + ))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -1216,14 +1186,11 @@ extern "C" fn new_request_number(n_args: usize, args: *const Obj, kwargs: *mut M .unwrap() }; - let obj = LayoutObj::new( - Frame::left_aligned( - theme::label_title(), - title, - NumberInputDialog::new(min_count, max_count, count, callback), - ) - .with_border(theme::borders()), - )?; + let obj = LayoutObj::new(Frame::left_aligned( + theme::label_title(), + title, + NumberInputDialog::new(min_count, max_count, count, callback), + ))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -1249,26 +1216,23 @@ extern "C" fn new_show_checklist(n_args: usize, args: *const Obj, kwargs: *mut M paragraphs.add(Paragraph::new(style, text)); } - let obj = LayoutObj::new( - Frame::left_aligned( - theme::label_title(), - title, - Dialog::new( - Checklist::from_paragraphs( - Icon::new(theme::ICON_LIST_CURRENT), - Icon::new(theme::ICON_LIST_CHECK), - active, - paragraphs - .into_paragraphs() - .with_spacing(theme::CHECKLIST_SPACING), - ), - theme::button_bar(Button::with_text(button).map(|msg| { - (matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed) - })), + let obj = LayoutObj::new(Frame::left_aligned( + theme::label_title(), + title, + Dialog::new( + Checklist::from_paragraphs( + Icon::new(theme::ICON_LIST_CURRENT), + Icon::new(theme::ICON_LIST_CHECK), + active, + paragraphs + .into_paragraphs() + .with_spacing(theme::CHECKLIST_SPACING), ), - ) - .with_border(theme::borders()), - )?; + theme::button_bar(Button::with_text(button).map(|msg| { + (matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed) + })), + ), + ))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } @@ -1346,14 +1310,11 @@ extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mu .centered(), ); - let obj = LayoutObj::new( - Frame::left_aligned( - theme::label_title(), - title, - Dialog::new(paragraphs, SelectWordCount::new()), - ) - .with_border(theme::borders()), - )?; + let obj = LayoutObj::new(Frame::left_aligned( + theme::label_title(), + title, + Dialog::new(paragraphs, SelectWordCount::new()), + ))?; Ok(obj.into()) }; unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } diff --git a/core/embed/rust/src/ui/model_tt/theme.rs b/core/embed/rust/src/ui/model_tt/theme.rs index 08416172ce..2aed27a4a4 100644 --- a/core/embed/rust/src/ui/model_tt/theme.rs +++ b/core/embed/rust/src/ui/model_tt/theme.rs @@ -553,22 +553,18 @@ pub const fn button_bar(inner: T) -> FixedHeightBar { } /// +----------+ -/// | 13 | +/// | 6 | /// | +----+ | -/// |10| |10| +/// | 6| | 6| /// | +----+ | -/// | 14 | +/// | 6 | /// +----------+ pub const fn borders() -> Insets { Insets::new(6, 6, 6, 6) } -pub const fn borders_scroll() -> Insets { - Insets::new(6, 6, 6, 6) -} - pub const fn borders_horizontal_scroll() -> Insets { - Insets::new(13, 10, 0, 10) + Insets::new(6, 6, 0, 6) } pub const fn borders_notification() -> Insets {