mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-08-02 11:58:32 +00:00
fix(core/ui): style update: buttons
[no changelog]
This commit is contained in:
parent
a8e7ad97b4
commit
f64fe18ad5
@ -26,7 +26,7 @@ pub use maybe::Maybe;
|
|||||||
pub use pad::Pad;
|
pub use pad::Pad;
|
||||||
pub use paginated::{AuxPageMsg, PageMsg, Paginate};
|
pub use paginated::{AuxPageMsg, PageMsg, Paginate};
|
||||||
pub use painter::Painter;
|
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 qr_code::Qr;
|
||||||
pub use text::{
|
pub use text::{
|
||||||
formatted::FormattedText,
|
formatted::FormattedText,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
component::{Component, Event, EventCtx},
|
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> {
|
pub struct GridPlaced<T> {
|
||||||
@ -195,25 +195,35 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VSplit<T, U> {
|
pub struct Split<T, U> {
|
||||||
first: T,
|
first: T,
|
||||||
second: U,
|
second: U,
|
||||||
width: i16,
|
axis: Axis,
|
||||||
|
size: i16,
|
||||||
spacing: i16,
|
spacing: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> VSplit<T, U> {
|
impl<T, U> Split<T, U> {
|
||||||
pub const fn new(width: i16, spacing: i16, first: T, second: U) -> Self {
|
pub const fn new(axis: Axis, size: i16, spacing: i16, first: T, second: U) -> Self {
|
||||||
Self {
|
Self {
|
||||||
first,
|
first,
|
||||||
second,
|
second,
|
||||||
width,
|
axis,
|
||||||
|
size,
|
||||||
spacing,
|
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
|
where
|
||||||
T: Component<Msg = M>,
|
T: Component<Msg = M>,
|
||||||
U: Component<Msg = M>,
|
U: Component<Msg = M>,
|
||||||
@ -221,10 +231,26 @@ where
|
|||||||
type Msg = M;
|
type Msg = M;
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
let (left, right) = bounds.split_left(self.width);
|
let size = if self.size == 0 {
|
||||||
let right = right.inset(Insets::left(self.spacing));
|
(bounds.size().axis(self.axis.cross()) - self.spacing) / 2
|
||||||
self.first.place(left);
|
} else {
|
||||||
self.second.place(right);
|
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
|
bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,13 +267,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ui_debug")]
|
#[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
|
where
|
||||||
T: Component + crate::trace::Trace,
|
T: Component + crate::trace::Trace,
|
||||||
U: Component + crate::trace::Trace,
|
U: Component + crate::trace::Trace,
|
||||||
{
|
{
|
||||||
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
fn trace(&self, d: &mut dyn crate::trace::Tracer) {
|
||||||
d.open("VSplit");
|
d.open("Split");
|
||||||
d.field("first", &self.first);
|
d.field("first", &self.first);
|
||||||
d.field("second", &self.second);
|
d.field("second", &self.second);
|
||||||
d.close();
|
d.close();
|
||||||
|
@ -2,8 +2,8 @@ use crate::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
ui::{
|
ui::{
|
||||||
component::{
|
component::{
|
||||||
Component, ComponentExt, Event, EventCtx, FixedHeightBar, Floating, GridPlaced, Map,
|
Component, ComponentExt, Event, EventCtx, FixedHeightBar, Floating, Map, Paginate,
|
||||||
Paginate, TimerToken, VSplit,
|
Split, TimerToken,
|
||||||
},
|
},
|
||||||
display::{self, toif::Icon, Color, Font},
|
display::{self, toif::Icon, Color, Font},
|
||||||
event::TouchEvent,
|
event::TouchEvent,
|
||||||
@ -63,16 +63,16 @@ impl<T> Button<T> {
|
|||||||
Self::new(ButtonContent::IconBlend(bg, fg, fg_offset))
|
Self::new(ButtonContent::IconBlend(bg, fg, fg_offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub const fn empty() -> Self {
|
||||||
Self::new(ButtonContent::Empty)
|
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.styles = styles;
|
||||||
self
|
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.touch_expand = Some(expand);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -377,7 +377,7 @@ impl<T> Button<T> {
|
|||||||
pub fn cancel_confirm(
|
pub fn cancel_confirm(
|
||||||
left: Button<T>,
|
left: Button<T>,
|
||||||
right: Button<T>,
|
right: Button<T>,
|
||||||
right_size_factor: usize,
|
left_is_small: bool,
|
||||||
) -> CancelConfirm<
|
) -> CancelConfirm<
|
||||||
T,
|
T,
|
||||||
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
|
impl Fn(ButtonMsg) -> Option<CancelConfirmMsg>,
|
||||||
@ -386,59 +386,13 @@ impl<T> Button<T> {
|
|||||||
where
|
where
|
||||||
T: AsRef<str>,
|
T: AsRef<str>,
|
||||||
{
|
{
|
||||||
let columns = 1 + right_size_factor;
|
let width = if left_is_small {
|
||||||
theme::button_bar((
|
theme::BUTTON_WIDTH
|
||||||
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)
|
|
||||||
} else {
|
} else {
|
||||||
(Button::with_icon(Icon::new(theme::ICON_CANCEL)), 2)
|
0
|
||||||
};
|
};
|
||||||
let right = Button::with_text(right).styled(theme::button_confirm());
|
theme::button_bar(Split::vertical(
|
||||||
|
width,
|
||||||
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_SPACING,
|
theme::BUTTON_SPACING,
|
||||||
left.map(|msg| {
|
left.map(|msg| {
|
||||||
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelConfirmMsg::Cancelled)
|
(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(
|
pub fn cancel_info_confirm(
|
||||||
confirm: T,
|
confirm: T,
|
||||||
info: T,
|
info: T,
|
||||||
@ -461,69 +443,29 @@ impl<T> Button<T> {
|
|||||||
where
|
where
|
||||||
T: AsRef<str>,
|
T: AsRef<str>,
|
||||||
{
|
{
|
||||||
let right = Button::with_text(confirm).styled(theme::button_confirm());
|
let right = Button::with_text(confirm)
|
||||||
let top = Button::with_text(info);
|
.styled(theme::button_confirm())
|
||||||
let left = Button::with_icon(Icon::new(theme::ICON_CANCEL));
|
.map(|msg| {
|
||||||
theme::button_bar_rows(
|
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Confirmed)
|
||||||
2,
|
});
|
||||||
(
|
let top = Button::with_text(info)
|
||||||
GridPlaced::new(left)
|
.styled(theme::button_moreinfo())
|
||||||
.with_grid(2, 3)
|
.map(|msg| (matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Info));
|
||||||
.with_spacing(theme::BUTTON_SPACING)
|
let left = Button::with_icon(Icon::new(theme::ICON_CANCEL)).map(|msg| {
|
||||||
.with_row_col(1, 0)
|
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled)
|
||||||
.map(|msg| {
|
});
|
||||||
(matches!(msg, ButtonMsg::Clicked)).then(|| CancelInfoConfirmMsg::Cancelled)
|
let total_height = theme::BUTTON_HEIGHT + theme::BUTTON_SPACING + theme::INFO_BUTTON_HEIGHT;
|
||||||
}),
|
FixedHeightBar::bottom(
|
||||||
GridPlaced::new(top)
|
Split::horizontal(
|
||||||
.with_grid(2, 3)
|
theme::INFO_BUTTON_HEIGHT,
|
||||||
.with_spacing(theme::BUTTON_SPACING)
|
theme::BUTTON_SPACING,
|
||||||
.with_from_to((0, 0), (0, 2))
|
top,
|
||||||
.map(|msg| {
|
Split::vertical(theme::BUTTON_WIDTH, theme::BUTTON_SPACING, left, right),
|
||||||
(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)
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
|
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(
|
pub fn select_word(
|
||||||
words: [T; 3],
|
words: [T; 3],
|
||||||
) -> CancelInfoConfirm<
|
) -> CancelInfoConfirm<
|
||||||
@ -536,38 +478,41 @@ impl<T> Button<T> {
|
|||||||
T: AsRef<str>,
|
T: AsRef<str>,
|
||||||
{
|
{
|
||||||
let btn = move |i, word| {
|
let btn = move |i, word| {
|
||||||
GridPlaced::new(Button::with_text(word))
|
Button::with_text(word)
|
||||||
.with_grid(3, 1)
|
.styled(theme::button_pin())
|
||||||
.with_spacing(theme::BUTTON_SPACING)
|
|
||||||
.with_row_col(i, 0)
|
|
||||||
.map(move |msg| {
|
.map(move |msg| {
|
||||||
(matches!(msg, ButtonMsg::Clicked)).then(|| SelectWordMsg::Selected(i))
|
(matches!(msg, ButtonMsg::Clicked)).then(|| SelectWordMsg::Selected(i))
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let [top, middle, bottom] = words;
|
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 {
|
pub enum CancelConfirmMsg {
|
||||||
Cancelled,
|
Cancelled,
|
||||||
Confirmed,
|
Confirmed,
|
||||||
}
|
}
|
||||||
|
|
||||||
type CancelInfoConfirm<T, F0, F1, F2> = FixedHeightBar<(
|
type CancelInfoConfirm<T, F0, F1, F2> =
|
||||||
Map<GridPlaced<Button<T>>, F0>,
|
FixedHeightBar<Split<Map<Button<T>, F0>, Split<Map<Button<T>, F1>, Map<Button<T>, F2>>>>;
|
||||||
Map<GridPlaced<Button<T>>, F1>,
|
|
||||||
Map<GridPlaced<Button<T>>, F2>,
|
|
||||||
)>;
|
|
||||||
|
|
||||||
type CancelConfirmSquare<T, F0, F1> =
|
type CancelConfirm<T, F0, F1> = FixedHeightBar<Split<Map<Button<T>, F0>, Map<Button<T>, F1>>>;
|
||||||
FixedHeightBar<VSplit<Map<Button<T>, F0>, Map<Button<T>, F1>>>;
|
|
||||||
|
|
||||||
pub enum CancelInfoConfirmMsg {
|
pub enum CancelInfoConfirmMsg {
|
||||||
Cancelled,
|
Cancelled,
|
||||||
@ -658,7 +603,9 @@ where
|
|||||||
button: Floating::top_right(
|
button: Floating::top_right(
|
||||||
theme::CORNER_BUTTON_SIDE,
|
theme::CORNER_BUTTON_SIDE,
|
||||||
theme::CORNER_BUTTON_SPACING,
|
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()),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,11 +126,11 @@ where
|
|||||||
T: Component,
|
T: Component,
|
||||||
U: AsRef<str>,
|
U: AsRef<str>,
|
||||||
{
|
{
|
||||||
const HEIGHT: i16 = 32;
|
const HEIGHT: i16 = 36;
|
||||||
const COLOR: Color = theme::YELLOW;
|
const COLOR: Color = theme::YELLOW;
|
||||||
const TEXT_OFFSET: Offset = Offset::new(1, -2);
|
const TEXT_OFFSET: Offset = Offset::new(1, -2);
|
||||||
const ICON_SPACE: i16 = 8;
|
const ICON_SPACE: i16 = 8;
|
||||||
const BORDER: i16 = 8;
|
const BORDER: i16 = 6;
|
||||||
|
|
||||||
pub fn new(icon: Icon, title: U, content: T) -> Self {
|
pub fn new(icon: Icon, title: U, content: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -47,7 +47,9 @@ where
|
|||||||
.with_long_press(theme::ERASE_HOLD_DURATION),
|
.with_long_press(theme::ERASE_HOLD_DURATION),
|
||||||
)),
|
)),
|
||||||
input: Child::new(Maybe::hidden(theme::BG, input)),
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 action: Option<StrBuffer> = kwargs.get(Qstr::MP_QSTR_action)?.try_into_option()?;
|
||||||
let description: Option<StrBuffer> =
|
let description: Option<StrBuffer> =
|
||||||
kwargs.get(Qstr::MP_QSTR_description)?.try_into_option()?;
|
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
|
let verb_cancel: Option<StrBuffer> = kwargs
|
||||||
.get(Qstr::MP_QSTR_verb_cancel)
|
.get(Qstr::MP_QSTR_verb_cancel)
|
||||||
.unwrap_or_else(|_| Obj::const_none())
|
.unwrap_or_else(|_| Obj::const_none())
|
||||||
@ -452,7 +455,7 @@ fn confirm_blob(
|
|||||||
SwipeHoldPage::new(paragraphs, theme::BG),
|
SwipeHoldPage::new(paragraphs, theme::BG),
|
||||||
))?
|
))?
|
||||||
} else if let Some(verb) = verb {
|
} 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(
|
LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
title,
|
title,
|
||||||
@ -504,12 +507,7 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
|
|||||||
}
|
}
|
||||||
.into_paragraphs();
|
.into_paragraphs();
|
||||||
|
|
||||||
let buttons = Button::cancel_confirm(
|
let buttons = Button::cancel_confirm_text(None, Some("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 obj = LayoutObj::new(FloatingButton::top_right_corner(
|
let obj = LayoutObj::new(FloatingButton::top_right_corner(
|
||||||
Icon::new(theme::ICON_CORNER_INFO),
|
Icon::new(theme::ICON_CORNER_INFO),
|
||||||
Frame::left_aligned(
|
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),
|
SwipeHoldPage::new(paragraphs.into_paragraphs(), theme::BG),
|
||||||
))?
|
))?
|
||||||
} else {
|
} else {
|
||||||
let buttons = Button::cancel_confirm_text(None, "CONFIRM");
|
let buttons = Button::cancel_confirm_text(None, Some("CONFIRM"));
|
||||||
LayoutObj::new(Frame::left_aligned(
|
LayoutObj::new(Frame::left_aligned(
|
||||||
theme::label_title(),
|
theme::label_title(),
|
||||||
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."))),
|
_ => 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(
|
let obj = LayoutObj::new(
|
||||||
Frame::centered(
|
Frame::centered(
|
||||||
theme::label_title(),
|
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(
|
let buttons = Button::cancel_confirm(
|
||||||
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
||||||
Button::with_text(button).styled(theme::button_confirm()),
|
Button::with_text(button).styled(theme::button_confirm()),
|
||||||
3,
|
true,
|
||||||
);
|
);
|
||||||
let obj = LayoutObj::new(
|
let obj = LayoutObj::new(
|
||||||
Frame::left_aligned(
|
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(
|
let buttons = Button::cancel_confirm(
|
||||||
Button::with_text(verb_cancel),
|
Button::with_text(verb_cancel),
|
||||||
Button::with_text("CONFIRM".into()).styled(theme::button_confirm()),
|
Button::with_text("CONFIRM".into()).styled(theme::button_confirm()),
|
||||||
1,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let obj = LayoutObj::new(
|
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(
|
let buttons = Button::cancel_confirm(
|
||||||
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
||||||
Button::with_text("NEXT").styled(theme::button_confirm()),
|
Button::with_text("NEXT").styled(theme::button_confirm()),
|
||||||
2,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::left_aligned(
|
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(
|
let buttons = Button::cancel_confirm(
|
||||||
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
||||||
Button::with_text("NEXT").styled(theme::button_confirm()),
|
Button::with_text("NEXT").styled(theme::button_confirm()),
|
||||||
2,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::left_aligned(
|
let obj = LayoutObj::new(Frame::left_aligned(
|
||||||
@ -832,7 +830,7 @@ fn new_show_modal(
|
|||||||
Button::cancel_confirm(
|
Button::cancel_confirm(
|
||||||
Button::with_icon(Icon::new(theme::ICON_CANCEL)).styled(theme::button_cancel()),
|
Button::with_icon(Icon::new(theme::ICON_CANCEL)).styled(theme::button_cancel()),
|
||||||
Button::with_text(button).styled(button_style),
|
Button::with_text(button).styled(button_style),
|
||||||
2,
|
true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_description(description),
|
.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(
|
let controls = Button::cancel_confirm(
|
||||||
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
Button::with_icon(Icon::new(theme::ICON_CANCEL)),
|
||||||
Button::with_text("CONFIRM").styled(theme::button_confirm()),
|
Button::with_text("CONFIRM").styled(theme::button_confirm()),
|
||||||
2,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
let fido_page = FidoConfirm::new(app_name, get_page, page_count, icon, controls);
|
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(
|
IconDialog::new(
|
||||||
icon,
|
icon,
|
||||||
title,
|
title,
|
||||||
Button::cancel_confirm_square(
|
Button::cancel_confirm(
|
||||||
Button::with_icon(Icon::new(theme::ICON_BACK)),
|
Button::with_icon(Icon::new(theme::ICON_BACK)),
|
||||||
Button::with_text(button).styled(theme::button_reset()),
|
Button::with_text(button).styled(theme::button_reset()),
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.with_description(description)
|
.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_iterable: Obj = kwargs.get(Qstr::MP_QSTR_words)?;
|
||||||
let words: [StrBuffer; 3] = iter_into_array(words_iterable)?;
|
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 buttons = Button::select_word(words);
|
||||||
|
|
||||||
let obj = LayoutObj::new(Frame::left_aligned(
|
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(
|
LayoutObj::new(NotificationFrame::new(
|
||||||
Icon::new(theme::ICON_WARN),
|
Icon::new(theme::ICON_WARN),
|
||||||
notification,
|
notification,
|
||||||
Dialog::new(paragraphs, Button::<&'static str>::abort_info_enter()),
|
Dialog::new(
|
||||||
|
paragraphs,
|
||||||
|
Button::cancel_info_confirm("CONTINUE", "MORE INFO"),
|
||||||
|
),
|
||||||
))?
|
))?
|
||||||
} else {
|
} else {
|
||||||
LayoutObj::new(NotificationFrame::new(
|
LayoutObj::new(NotificationFrame::new(
|
||||||
Icon::new(theme::ICON_WARN),
|
Icon::new(theme::ICON_WARN),
|
||||||
notification,
|
notification,
|
||||||
Dialog::new(paragraphs, Button::cancel_confirm_text(None, button)),
|
Dialog::new(paragraphs, Button::cancel_confirm_text(None, Some(button))),
|
||||||
))?
|
))?
|
||||||
};
|
};
|
||||||
Ok(obj.into())
|
Ok(obj.into())
|
||||||
@ -1920,7 +1922,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn trace_example_layout() {
|
fn trace_example_layout() {
|
||||||
let buttons =
|
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(
|
let mut layout = Dialog::new(
|
||||||
FormattedText::new(
|
FormattedText::new(
|
||||||
theme::TEXT_NORMAL,
|
theme::TEXT_NORMAL,
|
||||||
|
@ -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 {
|
pub const fn button_info() -> ButtonStyleSheet {
|
||||||
ButtonStyleSheet {
|
ButtonStyleSheet {
|
||||||
normal: &ButtonStyle {
|
normal: &ButtonStyle {
|
||||||
@ -444,27 +476,21 @@ pub const FORMATTED: FormattedFonts = FormattedFonts {
|
|||||||
mono: Font::MONO,
|
mono: Font::MONO,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CONTENT_BORDER: i16 = 5;
|
pub const CONTENT_BORDER: i16 = 0;
|
||||||
pub const KEYBOARD_SPACING: i16 = 8;
|
pub const BUTTON_HEIGHT: i16 = 50;
|
||||||
pub const BUTTON_HEIGHT: i16 = 38;
|
pub const BUTTON_WIDTH: i16 = 56;
|
||||||
pub const BUTTON_SPACING: i16 = 6;
|
pub const BUTTON_SPACING: i16 = 6;
|
||||||
|
pub const KEYBOARD_SPACING: i16 = BUTTON_SPACING;
|
||||||
pub const CHECKLIST_SPACING: i16 = 10;
|
pub const CHECKLIST_SPACING: i16 = 10;
|
||||||
pub const RECOVERY_SPACING: i16 = 18;
|
pub const RECOVERY_SPACING: i16 = 18;
|
||||||
pub const CORNER_BUTTON_SIDE: i16 = 32;
|
pub const CORNER_BUTTON_SIDE: i16 = 44;
|
||||||
pub const CORNER_BUTTON_SPACING: i16 = 8;
|
pub const CORNER_BUTTON_SPACING: i16 = BUTTON_SPACING;
|
||||||
|
pub const INFO_BUTTON_HEIGHT: i16 = 44;
|
||||||
/// Standard button height in pixels.
|
pub const PIN_BUTTON_HEIGHT: i16 = 40;
|
||||||
pub const fn button_rows(count: usize) -> i16 {
|
pub const MNEMONIC_BUTTON_HEIGHT: i16 = 52;
|
||||||
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 fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
|
pub const fn button_bar<T>(inner: T) -> FixedHeightBar<T> {
|
||||||
button_bar_rows(1, inner)
|
FixedHeightBar::bottom(inner, BUTTON_HEIGHT)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// +----------+
|
/// +----------+
|
||||||
|
@ -213,7 +213,7 @@ async def confirm_action(
|
|||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
description_param: str | None = None,
|
description_param: str | None = None,
|
||||||
description_param_font: int = ui.BOLD,
|
description_param_font: int = ui.BOLD,
|
||||||
verb: str = "CONFIRM",
|
verb: str | None = None,
|
||||||
verb_cancel: str | None = None,
|
verb_cancel: str | None = None,
|
||||||
hold: bool = False,
|
hold: bool = False,
|
||||||
hold_danger: bool = False,
|
hold_danger: bool = False,
|
||||||
@ -221,6 +221,8 @@ async def confirm_action(
|
|||||||
exc: ExceptionType = ActionCancelled,
|
exc: ExceptionType = ActionCancelled,
|
||||||
br_code: ButtonRequestType = BR_TYPE_OTHER,
|
br_code: ButtonRequestType = BR_TYPE_OTHER,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
if verb is not None:
|
||||||
|
verb = verb.upper()
|
||||||
if verb_cancel is not None:
|
if verb_cancel is not None:
|
||||||
verb_cancel = verb_cancel.upper()
|
verb_cancel = verb_cancel.upper()
|
||||||
|
|
||||||
@ -237,7 +239,7 @@ async def confirm_action(
|
|||||||
title=title.upper(),
|
title=title.upper(),
|
||||||
action=action,
|
action=action,
|
||||||
description=description,
|
description=description,
|
||||||
verb=verb.upper(),
|
verb=verb,
|
||||||
verb_cancel=verb_cancel,
|
verb_cancel=verb_cancel,
|
||||||
hold=hold,
|
hold=hold,
|
||||||
hold_danger=hold_danger,
|
hold_danger=hold_danger,
|
||||||
|
@ -109,7 +109,7 @@ async def select_word(
|
|||||||
trezorui2.select_word(
|
trezorui2.select_word(
|
||||||
title=title,
|
title=title,
|
||||||
description=f"Select word {checked_index + 1} of {count}:",
|
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]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user