1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-18 12:28:09 +00:00

refactor(core/ui): VerticalMenu flexibility

This commit is contained in:
Martin Milata 2024-04-30 10:49:32 +02:00
parent cf53876292
commit b05b54dfd8
8 changed files with 46 additions and 80 deletions

View File

@ -536,7 +536,6 @@ static void _librust_qstrs(void) {
MP_QSTR_show_share_words; MP_QSTR_show_share_words;
MP_QSTR_show_simple; MP_QSTR_show_simple;
MP_QSTR_show_success; MP_QSTR_show_success;
MP_QSTR_show_tx_context_menu;
MP_QSTR_show_wait_text; MP_QSTR_show_wait_text;
MP_QSTR_show_warning; MP_QSTR_show_warning;
MP_QSTR_sign; MP_QSTR_sign;

View File

@ -503,7 +503,7 @@ pub enum CancelInfoConfirmMsg {
#[derive(PartialEq, Eq, Clone)] #[derive(PartialEq, Eq, Clone)]
pub struct IconText { pub struct IconText {
text: &'static str, text: TString<'static>,
icon: Icon, icon: Icon,
} }
@ -512,12 +512,15 @@ impl IconText {
const ICON_MARGIN: i16 = 4; const ICON_MARGIN: i16 = 4;
const TEXT_MARGIN: i16 = 6; const TEXT_MARGIN: i16 = 6;
pub fn new(text: &'static str, icon: Icon) -> Self { pub fn new(text: impl Into<TString<'static>>, icon: Icon) -> Self {
Self { text, icon } Self {
text: text.into(),
icon,
}
} }
pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: Offset) { pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: Offset) {
let width = style.font.text_width(self.text); let width = self.text.map(|t| style.font.text_width(t));
let height = style.font.text_height(); let height = style.font.text_height();
let mut use_icon = false; let mut use_icon = false;
@ -543,13 +546,15 @@ impl IconText {
} }
if use_text { if use_text {
self.text.map(|t| {
display::text_left( display::text_left(
text_pos, text_pos,
self.text, t,
style.font, style.font,
style.text_color, style.text_color,
style.button_color, style.button_color,
); )
});
} }
if use_icon { if use_icon {
@ -568,7 +573,7 @@ impl IconText {
style: &ButtonStyle, style: &ButtonStyle,
baseline_offset: Offset, baseline_offset: Offset,
) { ) {
let width = style.font.text_width(self.text.as_ref()); let width = self.text.map(|t| style.font.text_width(t));
let mut use_icon = false; let mut use_icon = false;
let mut use_text = false; let mut use_text = false;
@ -593,10 +598,12 @@ impl IconText {
} }
if use_text { if use_text {
shape::Text::new(text_pos, self.text) self.text.map(|t| {
shape::Text::new(text_pos, t)
.with_font(style.font) .with_font(style.font)
.with_fg(style.text_color) .with_fg(style.text_color)
.render(target); .render(target)
});
} }
if use_icon { if use_icon {

View File

@ -59,25 +59,23 @@ impl VerticalMenu {
Self::new(buttons_vec) Self::new(buttons_vec)
} }
pub fn context_menu(options: Vec<(&'static str, Icon), N_ITEMS>) -> Self { pub fn empty() -> Self {
// FIXME: args should be TString when IconText has TString Self::new(VerticalMenuButtons::new())
let mut buttons_vec = VerticalMenuButtons::new();
for opt in options {
let button_theme;
match opt.1 {
// FIXME: might not be applicable everywhere
theme::ICON_CANCEL => {
button_theme = theme::button_warning_high();
} }
_ => {
button_theme = theme::button_default(); pub fn item(mut self, icon: Icon, text: TString<'static>) -> Self {
} unwrap!(self.buttons.push(
} Button::with_icon_and_text(IconText::new(text, icon)).styled(theme::button_default())
unwrap!(buttons_vec.push(
Button::with_icon_and_text(IconText::new(opt.0, opt.1)).styled(button_theme)
)); ));
self
} }
Self::new(buttons_vec)
pub fn danger(mut self, icon: Icon, text: TString<'static>) -> Self {
unwrap!(self.buttons.push(
Button::with_icon_and_text(IconText::new(text, icon))
.styled(theme::button_warning_high())
));
self
} }
} }

View File

@ -11,7 +11,6 @@ use crate::{
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow, SwipePage}, flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow, SwipePage},
}, },
}; };
use heapless::Vec;
use super::super::{ use super::super::{
component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg}, component::{Frame, FrameMsg, PromptScreen, VerticalMenu, VerticalMenuChoiceMsg},
@ -91,10 +90,7 @@ impl ConfirmResetDevice {
let content_menu = Frame::left_aligned( let content_menu = Frame::left_aligned(
"".into(), "".into(),
VerticalMenu::context_menu(unwrap!(Vec::from_slice(&[( VerticalMenu::empty().danger(theme::ICON_CANCEL, "Cancel".into()),
"Cancel", // FIXME: use TString
theme::ICON_CANCEL
)]))),
) )
.with_cancel_button() .with_cancel_button()
.map(|msg| match msg { .map(|msg| match msg {

View File

@ -10,7 +10,6 @@ use crate::{
flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow, SwipePage}, flow::{base::Decision, flow_store, FlowMsg, FlowState, FlowStore, SwipeFlow, SwipePage},
}, },
}; };
use heapless::Vec;
use super::super::{ use super::super::{
component::{ component::{
@ -95,10 +94,7 @@ impl CreateBackup {
let content_menu = Frame::left_aligned( let content_menu = Frame::left_aligned(
"".into(), "".into(),
VerticalMenu::context_menu(unwrap!(Vec::from_slice(&[( VerticalMenu::empty().danger(theme::ICON_CANCEL, "Skip backup".into()),
"Skip backup", // FIXME: use TString
theme::ICON_CANCEL
)]))),
) )
.with_cancel_button() .with_cancel_button()
.map(|msg| match msg { .map(|msg| match msg {

View File

@ -12,7 +12,6 @@ use crate::{
}, },
}, },
}; };
use heapless::Vec;
use super::super::{ use super::super::{
component::{Frame, FrameMsg, IconDialog, VerticalMenu, VerticalMenuChoiceMsg}, component::{Frame, FrameMsg, IconDialog, VerticalMenu, VerticalMenuChoiceMsg},
@ -121,11 +120,10 @@ impl GetAddress {
.add( .add(
Frame::left_aligned( Frame::left_aligned(
"".into(), "".into(),
VerticalMenu::context_menu(unwrap!(Vec::from_slice(&[ VerticalMenu::empty()
("Address QR code", theme::ICON_QR_CODE), .item(theme::ICON_QR_CODE, "Address QR code".into())
("Account info", theme::ICON_CHEVRON_RIGHT), .item(theme::ICON_CHEVRON_RIGHT, "Account info".into())
("Cancel trans.", theme::ICON_CANCEL), .danger(theme::ICON_CANCEL, "Cancel operation".into()),
]))),
) )
.with_cancel_button() .with_cancel_button()
.map(|msg| match msg { .map(|msg| match msg {

View File

@ -1295,23 +1295,6 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map)
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) } unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
} }
extern "C" fn new_show_tx_context_menu(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], _kwargs: &Map| {
// TODO: this is just POC
let title: TString = "".into();
let options = unwrap!(Vec::from_slice(&[
("Address QR code", theme::ICON_QR_CODE),
("Fee info", theme::ICON_CHEVRON_RIGHT),
("Cancel transaction", theme::ICON_CANCEL),
]));
let content = VerticalMenu::context_menu(options);
let frame_with_menu = Frame::left_aligned(title, content).with_cancel_button();
let obj = LayoutObj::new(frame_with_menu)?;
Ok(obj.into())
};
unsafe { util::try_with_args_and_kwargs(n_args, args, kwargs, block) }
}
extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj { extern "C" fn new_show_share_words(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| { let block = move |_args: &[Obj], kwargs: &Map| {
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
@ -2040,11 +2023,6 @@ pub static mp_module_trezorui2: Module = obj_module! {
/// iterable must be of exact size. Returns index in range `0..3`.""" /// iterable must be of exact size. Returns index in range `0..3`."""
Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(), Qstr::MP_QSTR_select_word => obj_fn_kw!(0, new_select_word).as_obj(),
/// def show_tx_context_menu() -> LayoutObj[int]:
/// """Show transaction context menu with the options for 1) Address QR code, 2) Fee
/// information, 3) Cancel transaction"""
Qstr::MP_QSTR_show_tx_context_menu => obj_fn_kw!(0, new_show_tx_context_menu).as_obj(),
// TODO: This is just POC // TODO: This is just POC
/// def create_backup_flow() -> LayoutObj[UiResult] /// def create_backup_flow() -> LayoutObj[UiResult]
/// """Start create backup or skip flow.""" /// """Start create backup or skip flow."""

View File

@ -389,12 +389,6 @@ def select_word(
iterable must be of exact size. Returns index in range `0..3`.""" iterable must be of exact size. Returns index in range `0..3`."""
# rust/src/ui/model_mercury/layout.rs
def show_tx_context_menu() -> LayoutObj[int]:
"""Show transaction context menu with the options for 1) Address QR code, 2) Fee
information, 3) Cancel transaction"""
# rust/src/ui/model_mercury/layout.rs # rust/src/ui/model_mercury/layout.rs
def create_backup_flow() -> LayoutObj[UiResult] def create_backup_flow() -> LayoutObj[UiResult]
"""Start create backup or skip flow.""" """Start create backup or skip flow."""