1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-27 00:48:12 +00:00

perf(core/eckhart): constructing MenuItems

- self-referential builder pattern is easier on the stack memory usage
than consuming builder pattern
- store ButtonStyleSheet as a static ref
This commit is contained in:
obrusvit 2025-05-21 11:48:06 +02:00 committed by Vít Obrusník
parent bd89e13493
commit d73f0dc79d

View File

@ -70,26 +70,30 @@ pub enum DeviceMenuMsg {
struct MenuItem { struct MenuItem {
text: TString<'static>, text: TString<'static>,
subtext: Option<(TString<'static>, Option<TextStyle>)>, subtext: Option<(TString<'static>, Option<TextStyle>)>,
stylesheet: ButtonStyleSheet, stylesheet: &'static ButtonStyleSheet,
action: Option<Action>, action: Option<Action>,
} }
const MENU_ITEM_TITLE_STYLE_SHEET: &ButtonStyleSheet = &theme::menu_item_title();
impl MenuItem { impl MenuItem {
pub fn new(text: TString<'static>, action: Option<Action>) -> Self { pub fn new(text: TString<'static>, action: Option<Action>) -> Self {
Self { Self {
text, text,
subtext: None, subtext: None,
stylesheet: theme::menu_item_title(), stylesheet: MENU_ITEM_TITLE_STYLE_SHEET,
action, action,
} }
} }
pub fn with_subtext(mut self, subtext: Option<(TString<'static>, Option<TextStyle>)>) -> Self { pub fn with_subtext(
&mut self,
subtext: Option<(TString<'static>, Option<TextStyle>)>,
) -> &mut Self {
self.subtext = subtext; self.subtext = subtext;
self self
} }
pub fn with_stylesheet(mut self, stylesheet: ButtonStyleSheet) -> Self { pub fn with_stylesheet(&mut self, stylesheet: &'static ButtonStyleSheet) -> &mut Self {
self.stylesheet = stylesheet; self.stylesheet = stylesheet;
self self
} }
@ -221,12 +225,13 @@ impl<'a> DeviceMenuScreen<'a> {
) -> usize { ) -> usize {
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new(); let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
for (device, idx) in paired_devices.iter().zip(paired_device_indices) { for (device, idx) in paired_devices.iter().zip(paired_device_indices) {
unwrap!(items.push( let mut item_device = MenuItem::new(*device, Some(Action::GoTo(idx)));
MenuItem::new(*device, Some(Action::GoTo(idx))).with_subtext(Some(( // TODO: this should be a boolean feature of the device
"Connected".into(), item_device.with_subtext(Some((
Some(Button::SUBTEXT_STYLE_GREEN) "Connected".into(),
))) // TODO: this should be a boolean feature of the device Some(Button::SUBTEXT_STYLE_GREEN),
)); )));
unwrap!(items.push(item_device));
} }
let submenu_index = self.add_submenu(Submenu::new("Manage paired devices".into(), items)); let submenu_index = self.add_submenu(Submenu::new("Manage paired devices".into(), items));
@ -235,16 +240,15 @@ impl<'a> DeviceMenuScreen<'a> {
fn add_pair_and_connect_menu(&mut self, manage_devices_index: usize) -> usize { fn add_pair_and_connect_menu(&mut self, manage_devices_index: usize) -> usize {
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new(); let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
unwrap!(items.push( let mut manage_paired_item = MenuItem::new(
MenuItem::new( "Manage paired devices".into(),
"Manage paired devices".into(), Some(Action::GoTo(manage_devices_index)),
Some(Action::GoTo(manage_devices_index)), );
) manage_paired_item.with_subtext(Some((
.with_subtext(Some(( "1 device connected".into(),
"1 device connected".into(), Some(Button::SUBTEXT_STYLE_GREEN),
Some(Button::SUBTEXT_STYLE_GREEN) )));
))) unwrap!(items.push(manage_paired_item));
));
unwrap!(items.push(MenuItem::new( unwrap!(items.push(MenuItem::new(
"Pair new device".into(), "Pair new device".into(),
Some(Action::Return(DeviceMenuMsg::DevicePair)), Some(Action::Return(DeviceMenuMsg::DevicePair)),
@ -291,22 +295,21 @@ impl<'a> DeviceMenuScreen<'a> {
auto_lock_delay: TString<'static>, auto_lock_delay: TString<'static>,
) -> usize { ) -> usize {
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new(); let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
unwrap!( let mut item_device_name = MenuItem::new("Name".into(), None);
items.push(MenuItem::new("Name".into(), None).with_subtext(Some((device_name, None)))) item_device_name.with_subtext(Some((device_name, None)));
); unwrap!(items.push(item_device_name));
unwrap!(items.push(MenuItem::new( unwrap!(items.push(MenuItem::new(
"Screen brightness".into(), "Screen brightness".into(),
Some(Action::Return(DeviceMenuMsg::ScreenBrightness)), Some(Action::Return(DeviceMenuMsg::ScreenBrightness)),
))); )));
if has_pin() { if has_pin() {
unwrap!(items.push( let mut autolock_delay_item = MenuItem::new(
MenuItem::new( "Auto-lock delay".into(),
"Auto-lock delay".into(), Some(Action::Return(DeviceMenuMsg::AutoLockDelay)),
Some(Action::Return(DeviceMenuMsg::AutoLockDelay)), );
) autolock_delay_item.with_subtext(Some((auto_lock_delay, None)));
.with_subtext(Some((auto_lock_delay, None))) unwrap!(items.push(autolock_delay_item));
));
} }
unwrap!(items.push(MenuItem::new( unwrap!(items.push(MenuItem::new(
@ -326,25 +329,23 @@ impl<'a> DeviceMenuScreen<'a> {
) -> usize { ) -> usize {
let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new(); let mut items: Vec<MenuItem, SHORT_MENU_ITEMS> = Vec::new();
if failed_backup { if failed_backup {
unwrap!(items.push( let mut item_backup_failed = MenuItem::new(
MenuItem::new( "Backup failed".into(),
"Backup failed".into(), Some(Action::Return(DeviceMenuMsg::BackupFailed)),
Some(Action::Return(DeviceMenuMsg::BackupFailed)), );
) item_backup_failed.with_subtext(Some(("Review".into(), None)));
.with_subtext(Some(("Review".into(), None))) item_backup_failed.with_stylesheet(MENU_ITEM_TITLE_STYLE_SHEET);
.with_stylesheet(theme::menu_item_title_red()), unwrap!(items.push(item_backup_failed));
));
} }
unwrap!(items.push( let mut item_pair_and_connect = MenuItem::new(
MenuItem::new( "Pair & connect".into(),
"Pair & connect".into(), Some(Action::GoTo(pair_and_connect_index)),
Some(Action::GoTo(pair_and_connect_index)), );
) item_pair_and_connect.with_subtext(Some((
.with_subtext(Some(( "1 device connected".into(),
"1 device connected".into(), Some(Button::SUBTEXT_STYLE_GREEN),
Some(Button::SUBTEXT_STYLE_GREEN) )));
))) unwrap!(items.push(item_pair_and_connect));
));
unwrap!(items.push(MenuItem::new( unwrap!(items.push(MenuItem::new(
"Settings".into(), "Settings".into(),
Some(Action::GoTo(settings_index)), Some(Action::GoTo(settings_index)),
@ -379,12 +380,12 @@ impl<'a> DeviceMenuScreen<'a> {
let button = if let Some((subtext, subtext_style)) = item.subtext { let button = if let Some((subtext, subtext_style)) = item.subtext {
Button::new_menu_item_with_subtext( Button::new_menu_item_with_subtext(
item.text, item.text,
item.stylesheet, *item.stylesheet,
subtext, subtext,
subtext_style, subtext_style,
) )
} else { } else {
Button::new_menu_item(item.text, item.stylesheet) Button::new_menu_item(item.text, *item.stylesheet)
}; };
menu.item(button); menu.item(button);
} }