1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-08-01 03:18:12 +00:00

fix(core/ui): style update: buttons

[no changelog]
This commit is contained in:
Martin Milata 2023-03-07 22:21:27 +01:00
parent a8e7ad97b4
commit f64fe18ad5
9 changed files with 196 additions and 191 deletions

View File

@ -26,7 +26,7 @@ pub use maybe::Maybe;
pub use pad::Pad;
pub use paginated::{AuxPageMsg, PageMsg, Paginate};
pub use painter::Painter;
pub use placed::{FixedHeightBar, Floating, GridPlaced, VSplit};
pub use placed::{FixedHeightBar, Floating, GridPlaced, Split};
pub use qr_code::Qr;
pub use text::{
formatted::FormattedText,

View File

@ -1,6 +1,6 @@
use crate::ui::{
component::{Component, Event, EventCtx},
geometry::{Alignment, Alignment2D, Grid, GridCellSpan, Insets, Offset, Rect, TOP_RIGHT},
geometry::{Alignment, Alignment2D, Axis, Grid, GridCellSpan, Insets, Offset, Rect, TOP_RIGHT},
};
pub struct GridPlaced<T> {
@ -195,25 +195,35 @@ where
}
}
pub struct VSplit<T, U> {
pub struct Split<T, U> {
first: T,
second: U,
width: i16,
axis: Axis,
size: i16,
spacing: i16,
}
impl<T, U> VSplit<T, U> {
pub const fn new(width: i16, spacing: i16, first: T, second: U) -> Self {
impl<T, U> Split<T, U> {
pub const fn new(axis: Axis, size: i16, spacing: i16, first: T, second: U) -> Self {
Self {
first,
second,
width,
axis,
size,
spacing,
}
}
pub const fn vertical(size: i16, spacing: i16, first: T, second: U) -> Self {
Self::new(Axis::Vertical, size, spacing, first, second)
}
pub const fn horizontal(size: i16, spacing: i16, first: T, second: U) -> Self {
Self::new(Axis::Horizontal, size, spacing, first, second)
}
}
impl<M, T, U> Component for VSplit<T, U>
impl<M, T, U> Component for Split<T, U>
where
T: Component<Msg = M>,
U: Component<Msg = M>,
@ -221,10 +231,26 @@ where
type Msg = M;
fn place(&mut self, bounds: Rect) -> Rect {
let (left, right) = bounds.split_left(self.width);
let right = right.inset(Insets::left(self.spacing));
self.first.place(left);
self.second.place(right);
let size = if self.size == 0 {
(bounds.size().axis(self.axis.cross()) - self.spacing) / 2
} else {
self.size
};
let (first, second) = match self.axis {
Axis::Vertical if size > 0 => bounds.split_left(size),
Axis::Vertical => bounds.split_right(-size),
Axis::Horizontal if size > 0 => bounds.split_top(size),
Axis::Horizontal => bounds.split_bottom(-size),
};
let (first, second) = match self.axis {
Axis::Vertical if size > 0 => (first, second.inset(Insets::left(self.spacing))),
Axis::Vertical => (first.inset(Insets::right(self.spacing)), second),
Axis::Horizontal if size > 0 => (first, second.inset(Insets::top(self.spacing))),
Axis::Horizontal => (first.inset(Insets::bottom(self.spacing)), second),
};
self.first.place(first);
self.second.place(second);
bounds
}
@ -241,13 +267,13 @@ where
}
#[cfg(feature = "ui_debug")]
impl<T, U> crate::trace::Trace for VSplit<T, U>
impl<T, U> crate::trace::Trace for Split<T, U>
where
T: Component + crate::trace::Trace,
U: Component + crate::trace::Trace,
{
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
d.open("VSplit");
d.open("Split");
d.field("first", &self.first);
d.field("second", &self.second);
d.close();

View File

@ -2,8 +2,8 @@ use crate::{
time::Duration,
ui::{
component::{
Component, ComponentExt, Event, EventCtx, FixedHeightBar, Floating, GridPlaced, Map,
Paginate, TimerToken, VSplit,
Component, ComponentExt, Event, EventCtx, FixedHeightBar, Floating, Map, Paginate,
Split, TimerToken,
},
display::{self, toif::Icon, Color, Font},
event::TouchEvent,
@ -63,16 +63,16 @@ impl<T> Button<T> {
Self::new(ButtonContent::IconBlend(bg, fg, fg_offset))
}
pub fn empty() -> Self {
pub const fn empty() -> Self {
Self::new(ButtonContent::Empty)
}
pub fn styled(mut self, styles: ButtonStyleSheet) -> Self {
pub const fn styled(mut self, styles: ButtonStyleSheet) -> Self {
self.styles = styles;
self
}
pub fn with_expanded_touch_area(mut self, expand: Insets) -> Self {
pub const fn with_expanded_touch_area(mut self, expand: Insets) -> Self {
self.touch_expand = Some(expand);
self
}
@ -377,7 +377,7 @@ impl<T> Button<T> {
pub fn cancel_confirm(
left: Button<T>,
right: Button<T>,
right_size_factor: usize,
left_is_small: bool,
) -> CancelConfirm<
T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
@ -386,59 +386,13 @@ impl<T> Button<T> {
where
T: AsRef<str>,
{
let columns = 1 + right_size_factor;
theme::button_bar((
GridPlaced::new(left)
.with_grid(1, columns)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 0)
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Cancelled)
}),
GridPlaced::new(right)
.with_grid(1, columns)
.with_spacing(theme::BUTTON_SPACING)
.with_from_to((0, 1), (0, right_size_factor))
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Confirmed)
}),
))
}
pub fn cancel_confirm_text(
left: Option<T>,
right: T,
) -> CancelConfirm<
T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
>
where
T: AsRef<str>,
{
let (left, right_size_factor) = if let Some(verb) = left {
(Button::with_text(verb), 1)
let width = if left_is_small {
theme::BUTTON_WIDTH
} else {
(Button::with_icon(Icon::new(theme::ICON_CANCEL)), 2)
0
};
let right = Button::with_text(right).styled(theme::button_confirm());
Self::cancel_confirm(left, right, right_size_factor)
}
pub fn cancel_confirm_square(
left: Button<T>,
right: Button<T>,
) -> CancelConfirmSquare<
T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
>
where
T: AsRef<str>,
{
theme::button_bar(VSplit::new(
theme::BUTTON_HEIGHT,
theme::button_bar(Split::vertical(
width,
theme::BUTTON_SPACING,
left.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Cancelled)
@ -449,6 +403,34 @@ impl<T> Button<T> {
))
}
pub fn cancel_confirm_text(
left: Option<T>,
right: Option<T>,
) -> CancelConfirm<
T,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
>
where
T: AsRef<str>,
{
let left_is_small: bool;
let left = if let Some(verb) = left {
left_is_small = verb.as_ref().len() <= 4;
Button::with_text(verb)
} else {
left_is_small = right.is_some();
Button::with_icon(Icon::new(theme::ICON_CANCEL))
};
let right = if let Some(verb) = right {
Button::with_text(verb).styled(theme::button_confirm())
} else {
Button::with_icon(Icon::new(theme::ICON_CONFIRM)).styled(theme::button_confirm())
};
Self::cancel_confirm(left, right, left_is_small)
}
pub fn cancel_info_confirm(
confirm: T,
info: T,
@ -461,69 +443,29 @@ impl<T> Button<T> {
where
T: AsRef<str>,
{
let right = Button::with_text(confirm).styled(theme::button_confirm());
let top = Button::with_text(info);
let left = Button::with_icon(Icon::new(theme::ICON_CANCEL));
theme::button_bar_rows(
2,
(
GridPlaced::new(left)
.with_grid(2, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(1, 0)
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled)
}),
GridPlaced::new(top)
.with_grid(2, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_from_to((0, 0), (0, 2))
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Info)
}),
GridPlaced::new(right)
.with_grid(2, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_from_to((1, 1), (1, 2))
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Confirmed)
}),
let right = Button::with_text(confirm)
.styled(theme::button_confirm())
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Confirmed)
});
let top = Button::with_text(info)
.styled(theme::button_moreinfo())
.map(|msg| (matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Info));
let left = Button::with_icon(Icon::new(theme::ICON_CANCEL)).map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled)
});
let total_height = theme::BUTTON_HEIGHT + theme::BUTTON_SPACING + theme::INFO_BUTTON_HEIGHT;
FixedHeightBar::bottom(
Split::horizontal(
theme::INFO_BUTTON_HEIGHT,
theme::BUTTON_SPACING,
top,
Split::vertical(theme::BUTTON_WIDTH, theme::BUTTON_SPACING, left, right),
),
total_height,
)
}
pub fn abort_info_enter() -> CancelInfoConfirm<
&'static str,
impl Fn(ButtonMsg) -> Option<CancelInfoConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelInfoConfirmMsg>,
impl Fn(ButtonMsg) -> Option<CancelInfoConfirmMsg>,
> {
let left = Button::with_text("ABORT").styled(theme::button_cancel());
let middle = Button::with_text("INFO");
let right = Button::with_text("ENTER").styled(theme::button_confirm());
theme::button_bar((
GridPlaced::new(left)
.with_grid(1, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 0)
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled)
}),
GridPlaced::new(middle)
.with_grid(1, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 1)
.map(|msg| (matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Info)),
GridPlaced::new(right)
.with_grid(1, 3)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(0, 2)
.map(|msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Confirmed)
}),
))
}
pub fn select_word(
words: [T; 3],
) -> CancelInfoConfirm<
@ -536,38 +478,41 @@ impl<T> Button<T> {
T: AsRef<str>,
{
let btn = move |i, word| {
GridPlaced::new(Button::with_text(word))
.with_grid(3, 1)
.with_spacing(theme::BUTTON_SPACING)
.with_row_col(i, 0)
Button::with_text(word)
.styled(theme::button_pin())
.map(move |msg| {
(matches!(msg, ButtonMsg::Clicked)).then(|| SelectWordMsg::Selected(i))
})
};
let [top, middle, bottom] = words;
theme::button_bar_rows(3, (btn(0, top), btn(1, middle), btn(2, bottom)))
let total_height = 3 * theme::BUTTON_HEIGHT + 2 * theme::BUTTON_SPACING;
FixedHeightBar::bottom(
Split::horizontal(
theme::BUTTON_HEIGHT,
theme::BUTTON_SPACING,
btn(0, top),
Split::horizontal(
theme::BUTTON_HEIGHT,
theme::BUTTON_SPACING,
btn(1, middle),
btn(2, bottom),
),
),
total_height,
)
}
}
type CancelConfirm<T, F0, F1> = FixedHeightBar<(
Map<GridPlaced<Button<T>>, F0>,
Map<GridPlaced<Button<T>>, F1>,
)>;
pub enum CancelConfirmMsg {
Cancelled,
Confirmed,
}
type CancelInfoConfirm<T, F0, F1, F2> = FixedHeightBar<(
Map<GridPlaced<Button<T>>, F0>,
Map<GridPlaced<Button<T>>, F1>,
Map<GridPlaced<Button<T>>, F2>,
)>;
type CancelInfoConfirm<T, F0, F1, F2> =
FixedHeightBar<Split<Map<Button<T>, F0>, Split<Map<Button<T>, F1>, Map<Button<T>, F2>>>>;
type CancelConfirmSquare<T, F0, F1> =
FixedHeightBar<VSplit<Map<Button<T>, F0>, Map<Button<T>, F1>>>;
type CancelConfirm<T, F0, F1> = FixedHeightBar<Split<Map<Button<T>, F0>, Map<Button<T>, F1>>>;
pub enum CancelInfoConfirmMsg {
Cancelled,
@ -658,7 +603,9 @@ where
button: Floating::top_right(
theme::CORNER_BUTTON_SIDE,
theme::CORNER_BUTTON_SPACING,
Button::with_icon(icon),
Button::with_icon(icon)
.with_expanded_touch_area(Insets::uniform(theme::CORNER_BUTTON_SPACING))
.styled(theme::button_moreinfo()),
),
}
}

View File

@ -126,11 +126,11 @@ where
T: Component,
U: AsRef<str>,
{
const HEIGHT: i16 = 32;
const HEIGHT: i16 = 36;
const COLOR: Color = theme::YELLOW;
const TEXT_OFFSET: Offset = Offset::new(1, -2);
const ICON_SPACE: i16 = 8;
const BORDER: i16 = 8;
const BORDER: i16 = 6;
pub fn new(icon: Icon, title: U, content: T) -> Self {
Self {

View File

@ -47,7 +47,9 @@ where
.with_long_press(theme::ERASE_HOLD_DURATION),
)),
input: Child::new(Maybe::hidden(theme::BG, input)),
keys: T::keys().map(Button::with_text).map(Child::new),
keys: T::keys()
.map(|t| Button::with_text(t).styled(theme::button_pin()))
.map(Child::new),
}
}

View File

@ -381,7 +381,10 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
let action: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
let description: Option<StrBuffer> =
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
let verb: StrBuffer = kwargs.get_or(Qstr::MP_QSTR_verb, "CONFIRM".into())?;
let verb: Option<StrBuffer> = kwargs
.get(Qstr::MP_QSTR_verb)
.unwrap_or_else(|_| Obj::const_none())
.try_into_option()?;
let verb_cancel: Option<StrBuffer> = kwargs
.get(Qstr::MP_QSTR_verb_cancel)
.unwrap_or_else(|_| Obj::const_none())
@ -452,7 +455,7 @@ fn confirm_blob(
SwipeHoldPage::new(paragraphs, theme::BG),
))?
} else if let Some(verb) = verb {
let buttons = Button::cancel_confirm_text(verb_cancel, verb);
let buttons = Button::cancel_confirm_text(verb_cancel, Some(verb));
LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
@ -504,12 +507,7 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
}
.into_paragraphs();
let buttons = Button::cancel_confirm(
Button::<&'static str>::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::<&'static str>::with_icon(Icon::new(theme::ICON_CONFIRM))
.styled(theme::button_confirm()),
1,
);
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
let obj = LayoutObj::new(FloatingButton::top_right_corner(
Icon::new(theme::ICON_CORNER_INFO),
Frame::left_aligned(
@ -542,7 +540,7 @@ extern "C" fn new_confirm_properties(n_args: usize, args: *const Obj, kwargs: *m
SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG),
))?
} else {
let buttons = Button::cancel_confirm_text(None, "CONFIRM");
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
LayoutObj::new(Frame::left_aligned(
theme::label_title(),
title,
@ -570,7 +568,7 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m
_ => return Err(Error::ValueError(cstr!("Invalid image."))),
};
let buttons = Button::cancel_confirm_text(None, "CONFIRM");
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
let obj = LayoutObj::new(
Frame::centered(
theme::label_title(),
@ -602,7 +600,7 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs:
let buttons = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text(button).styled(theme::button_confirm()),
3,
true,
);
let obj = LayoutObj::new(
Frame::left_aligned(
@ -635,7 +633,7 @@ extern "C" fn new_show_qr(n_args: usize, args: *const Obj, kwargs: *mut Map) ->
let buttons = Button::cancel_confirm(
Button::with_text(verb_cancel),
Button::with_text("CONFIRM".into()).styled(theme::button_confirm()),
1,
false,
);
let obj = LayoutObj::new(
@ -746,7 +744,7 @@ extern "C" fn new_confirm_modify_output(n_args: usize, args: *const Obj, kwargs:
let buttons = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text("NEXT").styled(theme::button_confirm()),
2,
true,
);
let obj = LayoutObj::new(Frame::left_aligned(
@ -781,7 +779,7 @@ extern "C" fn new_confirm_modify_fee(n_args: usize, args: *const Obj, kwargs: *m
let buttons = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text("NEXT").styled(theme::button_confirm()),
2,
true,
);
let obj = LayoutObj::new(Frame::left_aligned(
@ -832,7 +830,7 @@ fn new_show_modal(
Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)).styled(theme::button_cancel()),
Button::with_text(button).styled(button_style),
2,
true,
),
)
.with_description(description),
@ -890,7 +888,7 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map
let controls = Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
Button::with_text("CONFIRM").styled(theme::button_confirm()),
2,
true,
);
let fido_page = FidoConfirm::new(app_name, get_page, page_count, icon, controls);
@ -963,9 +961,10 @@ extern "C" fn new_show_mismatch() -> Obj {
IconDialog::new(
icon,
title,
Button::cancel_confirm_square(
Button::cancel_confirm(
Button::with_icon(Icon::new(theme::ICON_BACK)),
Button::with_text(button).styled(theme::button_reset()),
true,
),
)
.with_description(description)
@ -1167,7 +1166,7 @@ extern "C" fn new_select_word(n_args: usize, args: *const Obj, kwargs: *mut Map)
let words_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?;
let words: [StrBuffer; 3] = iter_into_array(words_iterable)?;
let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_NORMAL, description)]);
let paragraphs = Paragraphs::new([Paragraph::new(&theme::TEXT_DEMIBOLD, description)]);
let buttons = Button::select_word(words);
let obj = LayoutObj::new(Frame::left_aligned(
@ -1315,13 +1314,16 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
LayoutObj::new(NotificationFrame::new(
Icon::new(theme::ICON_WARN),
notification,
Dialog::new(paragraphs, Button::<&'static str>::abort_info_enter()),
Dialog::new(
paragraphs,
Button::cancel_info_confirm("CONTINUE", "MORE INFO"),
),
))?
} else {
LayoutObj::new(NotificationFrame::new(
Icon::new(theme::ICON_WARN),
notification,
Dialog::new(paragraphs, Button::cancel_confirm_text(None, button)),
Dialog::new(paragraphs, Button::cancel_confirm_text(None, Some(button))),
))?
};
Ok(obj.into())
@ -1920,7 +1922,7 @@ mod tests {
#[test]
fn trace_example_layout() {
let buttons =
Button::cancel_confirm(Button::with_text("Left"), Button::with_text("Right"), 1);
Button::cancel_confirm(Button::with_text("Left"), Button::with_text("Right"), false);
let mut layout = Dialog::new(
FormattedText::new(
theme::TEXT_NORMAL,

View File

@ -288,6 +288,38 @@ pub const fn button_reset() -> ButtonStyleSheet {
}
}
pub const fn button_moreinfo() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {
font: Font::BOLD,
text_color: FG,
button_color: BG,
background_color: BG,
border_color: GREY_DARK,
border_radius: RADIUS,
border_width: 2,
},
active: &ButtonStyle {
font: Font::BOLD,
text_color: FG,
button_color: BG,
background_color: BG,
border_color: FG,
border_radius: RADIUS,
border_width: 2,
},
disabled: &ButtonStyle {
font: Font::BOLD,
text_color: GREY_LIGHT,
button_color: BG,
background_color: BG,
border_color: GREY_DARK,
border_radius: RADIUS,
border_width: 2,
},
}
}
pub const fn button_info() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {
@ -444,27 +476,21 @@ pub const FORMATTED: FormattedFonts = FormattedFonts {
mono: Font::MONO,
};
pub const CONTENT_BORDER: i16 = 5;
pub const KEYBOARD_SPACING: i16 = 8;
pub const BUTTON_HEIGHT: i16 = 38;
pub const CONTENT_BORDER: i16 = 0;
pub const BUTTON_HEIGHT: i16 = 50;
pub const BUTTON_WIDTH: i16 = 56;
pub const BUTTON_SPACING: i16 = 6;
pub const KEYBOARD_SPACING: i16 = BUTTON_SPACING;
pub const CHECKLIST_SPACING: i16 = 10;
pub const RECOVERY_SPACING: i16 = 18;
pub const CORNER_BUTTON_SIDE: i16 = 32;
pub const CORNER_BUTTON_SPACING: i16 = 8;
/// Standard button height in pixels.
pub const fn button_rows(count: usize) -> i16 {
let count = count as i16;
BUTTON_HEIGHT * count + BUTTON_SPACING * count.saturating_sub(1)
}
pub const fn button_bar_rows<T>(rows: usize, inner: T) -> FixedHeightBar<T> {
FixedHeightBar::bottom(inner, button_rows(rows))
}
pub const CORNER_BUTTON_SIDE: i16 = 44;
pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING;
pub const INFO_BUTTON_HEIGHT: i16 = 44;
pub const PIN_BUTTON_HEIGHT: i16 = 40;
pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52;
pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
button_bar_rows(1, inner)
FixedHeightBar::bottom(inner, BUTTON_HEIGHT)
}
/// +----------+

View File

@ -213,7 +213,7 @@ async def confirm_action(
description: str | None = None,
description_param: str | None = None,
description_param_font: int = ui.BOLD,
verb: str = "CONFIRM",
verb: str | None = None,
verb_cancel: str | None = None,
hold: bool = False,
hold_danger: bool = False,
@ -221,6 +221,8 @@ async def confirm_action(
exc: ExceptionType = ActionCancelled,
br_code: ButtonRequestType = BR_TYPE_OTHER,
) -> None:
if verb is not None:
verb = verb.upper()
if verb_cancel is not None:
verb_cancel = verb_cancel.upper()
@ -237,7 +239,7 @@ async def confirm_action(
title=title.upper(),
action=action,
description=description,
verb=verb.upper(),
verb=verb,
verb_cancel=verb_cancel,
hold=hold,
hold_danger=hold_danger,

View File

@ -109,7 +109,7 @@ async def select_word(
trezorui2.select_word(
title=title,
description=f"Select word {checked_index + 1} of {count}:",
words=(words[0].upper(), words[1].upper(), words[2].upper()),
words=(words[0], words[1], words[2]),
)
)
)