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

fix(core/ui): Model T style update

[no changelog]
This commit is contained in:
Martin Milata 2023-03-06 18:54:23 +01:00
parent 3623f966dc
commit 19a2ea21b6
115 changed files with 489 additions and 377 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

BIN
core/assets/bg-back52.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

BIN
core/assets/caret-up24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
core/assets/check16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

BIN
core/assets/check24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

BIN
core/assets/circle48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

BIN
core/assets/coinjoin16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

BIN
core/assets/fg-check48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

BIN
core/assets/fg-error48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

BIN
core/assets/fg-info48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

BIN
core/assets/fg-user48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

BIN
core/assets/info32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

Before

Width:  |  Height:  |  Size: 182 B

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

BIN
core/assets/octagon48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

BIN
core/assets/warning16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

BIN
core/assets/x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

BIN
core/assets/x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

View File

@ -27,7 +27,7 @@
#define BUFFER_PIXELS DISPLAY_RESX
#define TEXT_BUFFER_HEIGHT 32
#define TEXT_BUFFER_HEIGHT 36
#if TEXT_BUFFER_HEIGHT < FONT_MAX_HEIGHT
#error Text buffer height is too small, please adjust to match used fonts

View File

@ -149,7 +149,7 @@ void display_bar_radius(int x, int y, int w, int h, uint16_t c, uint16_t b,
void display_bar_radius_buffer(int x, int y, int w, int h, uint8_t r,
buffer_text_t *buffer) {
if (h > 32) {
if (h > TEXT_BUFFER_HEIGHT) {
return;
}
if (r != 2 && r != 4 && r != 8 && r != 16) {

View File

@ -29,6 +29,7 @@
/// FONT_MONO: int # id of monospace font
/// FONT_NORMAL: int # id of normal-width font
/// FONT_BOLD: int # id of bold-width font
/// FONT_DEMIBOLD: int # id of demibold font
/// TOIF_FULL_COLOR_BE: int # full color big endian TOI image
/// TOIF_FULL_COLOR_LE: int # full color little endian TOI image
/// TOIF_GRAYSCALE_EH: int # grayscale even high TOI image
@ -621,6 +622,7 @@ STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = {
{MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(DISPLAY_RESY)},
{MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_ROM_INT(FONT_NORMAL)},
{MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_ROM_INT(FONT_BOLD)},
{MP_ROM_QSTR(MP_QSTR_FONT_DEMIBOLD), MP_ROM_INT(FONT_DEMIBOLD)},
{MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_ROM_INT(FONT_MONO)},
{MP_ROM_QSTR(MP_QSTR_TOIF_FULL_COLOR_BE), MP_ROM_INT(TOIF_FULL_COLOR_BE)},
{MP_ROM_QSTR(MP_QSTR_TOIF_FULL_COLOR_LE), MP_ROM_INT(TOIF_FULL_COLOR_LE)},

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

@ -56,8 +56,8 @@ pub const TITLE_AREA_START_Y: i16 = 8;
pub const BUTTON_AREA_START: i16 = 188;
// UI icons.
pub const ICON_CANCEL: &[u8] = include_res!("model_tt/res/cancel.toif");
pub const ICON_CONFIRM: &[u8] = include_res!("model_tt/res/confirm.toif");
pub const ICON_CANCEL: &[u8] = include_res!("model_tt/res/x24.toif");
pub const ICON_CONFIRM: &[u8] = include_res!("model_tt/res/check24.toif");
// BLD icons
pub const CLOSE: &[u8] = include_res!("model_tt/res/close.toif");

View File

@ -15,24 +15,30 @@ use crate::{
use super::{theme, Frame};
const MAX_XPUBS: usize = 16;
pub struct AddressDetails<T> {
qr_code: Frame<Qr, T>,
details: Frame<Paragraphs<ParagraphVecShort<T>>, T>,
xpub_view: Frame<Paragraphs<Paragraph<T>>, T>,
xpubs: Vec<(T, T), 16>,
xpubs: Vec<(T, T), MAX_XPUBS>,
xpub_page_count: Vec<u8, MAX_XPUBS>,
current_page: usize,
}
impl<T> AddressDetails<T>
where
T: ParagraphStrType + From<&'static str>,
T: ParagraphStrType,
{
pub fn new(
qr_address: T,
case_sensitive: bool,
account: Option<T>,
path: Option<T>,
) -> Result<Self, Error> {
) -> Result<Self, Error>
where
T: From<&'static str>,
{
let mut para = ParagraphVecShort::new();
if let Some(a) = account {
para.add(Paragraph::new(&theme::TEXT_NORMAL, "Account:".into()));
@ -61,10 +67,11 @@ where
xpub_view: Frame::left_aligned(
theme::label_title(),
" \n ".into(),
Paragraph::new(&theme::TEXT_XPUB, "".into()).into_paragraphs(),
Paragraph::new(&theme::TEXT_MONO, "".into()).into_paragraphs(),
)
.with_border(theme::borders_horizontal_scroll()),
xpubs: Vec::new(),
xpub_page_count: Vec::new(),
current_page: 0,
};
Ok(result)
@ -75,6 +82,41 @@ where
.push((title, xpub))
.map_err(|_| Error::OutOfRange)
}
fn switch_xpub(&mut self, i: usize, page: usize) -> usize
where
T: Clone,
{
// Context is needed for updating child so that it can request repaint. In this
// case the parent component that handles paging always requests complete
// repaint after page change so we can use a dummy context here.
let mut dummy_ctx = EventCtx::new();
self.xpub_view
.update_title(&mut dummy_ctx, self.xpubs[i].0.clone());
self.xpub_view.update_content(&mut dummy_ctx, |p| {
p.inner_mut().update(self.xpubs[i].1.clone());
let npages = p.page_count();
p.change_page(page);
npages
})
}
fn lookup(&self, scrollbar_page: usize) -> (usize, usize) {
let mut xpub_index = 0;
let mut xpub_page = scrollbar_page;
for page_count in self.xpub_page_count.iter().map(|pc| {
let upc: usize = (*pc).into();
upc
}) {
if page_count <= xpub_page {
xpub_page -= page_count;
xpub_index += 1;
} else {
break;
}
}
(xpub_index, xpub_page)
}
}
impl<T> Paginate for AddressDetails<T>
@ -82,30 +124,23 @@ where
T: ParagraphStrType + Clone,
{
fn page_count(&mut self) -> usize {
2 + self.xpubs.len()
let total_xpub_pages: u8 = self.xpub_page_count.iter().copied().sum();
2usize.saturating_add(total_xpub_pages.into())
}
fn change_page(&mut self, to_page: usize) {
self.current_page = to_page;
if to_page > 1 {
let i = to_page - 2;
// Context is needed for updating child so that it can request repaint. In this
// case the parent component that handles paging always requests complete
// repaint after page change so we can use a dummy context here.
let mut dummy_ctx = EventCtx::new();
self.xpub_view
.update_title(&mut dummy_ctx, self.xpubs[i].0.clone());
self.xpub_view.update_content(&mut dummy_ctx, |p| {
p.inner_mut().update(self.xpubs[i].1.clone());
p.change_page(0)
});
let (xpub_index, xpub_page) = self.lookup(i);
self.switch_xpub(xpub_index, xpub_page);
}
}
}
impl<T> Component for AddressDetails<T>
where
T: ParagraphStrType,
T: ParagraphStrType + Clone,
{
type Msg = Never;
@ -113,6 +148,13 @@ where
self.qr_code.place(bounds);
self.details.place(bounds);
self.xpub_view.place(bounds);
self.xpub_page_count.clear();
for i in 0..self.xpubs.len() {
let npages = self.switch_xpub(i, 0) as u8;
unwrap!(self.xpub_page_count.push(npages));
}
bounds
}

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,
@ -33,7 +33,7 @@ pub struct Button<T> {
impl<T> Button<T> {
/// Offsets the baseline of the button text either up (negative) or down
/// (positive).
pub const BASELINE_OFFSET: i16 = -3;
pub const BASELINE_OFFSET: i16 = -2;
pub const fn new(content: ButtonContent<T>) -> Self {
Self {
@ -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

@ -60,8 +60,8 @@ where
page_swipe.allow_left = scrollbar.has_next_page();
Self {
app_name: Label::new(app_name, Alignment::Center, theme::TEXT_BOLD),
account_name: Label::new("".into(), Alignment::Center, theme::TEXT_BOLD),
app_name: Label::new(app_name, Alignment::Center, theme::TEXT_DEMIBOLD),
account_name: Label::new("".into(), Alignment::Center, theme::TEXT_DEMIBOLD),
page_swipe,
icon: Child::new(Image::new(icon_data)),
get_account,

View File

@ -3,9 +3,8 @@ use crate::ui::{
component::{
base::ComponentExt, label::Label, text::TextStyle, Child, Component, Event, EventCtx,
},
display::{self, toif::Icon, Color},
display::{self, Color, Font},
geometry::{Alignment, Insets, Offset, Rect},
util::icon_text_center,
};
pub struct Frame<T, U> {
@ -55,13 +54,14 @@ where
})
}
pub fn update_content<F>(&mut self, ctx: &mut EventCtx, update_fn: F)
pub fn update_content<F, R>(&mut self, ctx: &mut EventCtx, update_fn: F) -> R
where
F: Fn(&mut T),
F: Fn(&mut T) -> R,
{
self.content.mutate(ctx, |ctx, c| {
update_fn(c);
c.request_complete_repaint(ctx)
let res = update_fn(c);
c.request_complete_repaint(ctx);
res
})
}
}
@ -116,7 +116,6 @@ where
pub struct NotificationFrame<T, U> {
area: Rect,
icon: Icon,
title: U,
content: Child<T>,
}
@ -126,15 +125,12 @@ 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 {
pub fn new(title: U, content: T) -> Self {
Self {
icon,
title,
area: Rect::zero(),
content: Child::new(content),
@ -145,22 +141,18 @@ where
self.content.inner()
}
pub fn paint_notification(area: Rect, icon: Icon, title: &str, color: Color) {
pub fn paint_notification(area: Rect, title: &str, color: Color) {
let (area, _) = area
.inset(Insets::uniform(Self::BORDER))
.split_top(Self::HEIGHT);
let style = TextStyle {
background_color: color,
..theme::TEXT_BOLD
};
let font = Font::BOLD;
display::rect_fill_rounded(area, color, theme::BG, 2);
icon_text_center(
area.center(),
icon,
Self::ICON_SPACE,
display::text_center(
area.center() + Offset::y((font.text_max_height() - font.text_baseline()) / 2),
title,
style,
Self::TEXT_OFFSET,
Font::BOLD,
theme::FG,
color,
);
}
}
@ -184,7 +176,7 @@ where
}
fn paint(&mut self) {
Self::paint_notification(self.area, self.icon, self.title.as_ref(), Self::COLOR);
Self::paint_notification(self.area, self.title.as_ref(), Self::COLOR);
self.content.paint();
}

View File

@ -22,7 +22,7 @@ use super::{theme, Loader, LoaderMsg};
const AREA: Rect = constant::screen();
const TOP_CENTER: Point = AREA.top_center();
const LABEL_Y: i16 = 216;
const LABEL_Y: i16 = 222;
const LOCKED_Y: i16 = 107;
const TAP_Y: i16 = 134;
const HOLD_Y: i16 = 35;
@ -181,7 +181,7 @@ where
if self.loader.is_animating() || self.loader.is_completely_grown(Instant::now()) {
self.paint_loader();
} else {
let mut label_style = theme::TEXT_BOLD;
let mut label_style = theme::TEXT_DEMIBOLD;
label_style.text_color = theme::FG;
let text = HomescreenText {
@ -262,10 +262,7 @@ where
("LOCKED", "Tap to unlock")
};
let mut tap_style = theme::TEXT_NORMAL;
tap_style.text_color = theme::OFF_WHITE;
let mut label_style = theme::TEXT_BOLD;
let mut label_style = theme::TEXT_DEMIBOLD;
label_style.text_color = theme::GREY_LIGHT;
let texts: [HomescreenText; 3] = [
@ -277,7 +274,7 @@ where
},
HomescreenText {
text: tap,
style: tap_style,
style: theme::TEXT_NORMAL,
offset: Offset::new(10, TAP_Y),
icon: None,
},

View File

@ -53,19 +53,20 @@ struct HomescreenTextInfo {
pub const HOMESCREEN_IMAGE_SIZE: i16 = 240;
const HOMESCREEN_MAX_ICON_SIZE: i16 = 20;
const NOTIFICATION_HEIGHT: i16 = 32;
const NOTIFICATION_BORDER: i16 = 8;
const NOTIFICATION_HEIGHT: i16 = 36;
const NOTIFICATION_BORDER: i16 = 6;
const NOTIFICATION_ICON_SPACE: i16 = 8;
const NOTIFICATION_TEXT_OFFSET: Offset = Offset::new(1, -2);
const TEXT_ICON_SPACE: i16 = 2;
const HOMESCREEN_DIM_HIEGHT: i16 = 30;
const HOMESCREEN_DIM_START: i16 = 195;
const HOMESCREEN_DIM: f32 = 0.85;
const HOMESCREEN_DIM_BORDER: i16 = 20;
const HOMESCREEN_DIM_HEIGHT: i16 = 35;
const HOMESCREEN_DIM_START: i16 = 198;
const HOMESCREEN_DIM: f32 = 0.65;
const HOMESCREEN_DIM_BORDER: i16 = theme::BUTTON_SPACING;
const LOCKSCREEN_DIM: f32 = 0.85;
const LOCKSCREEN_DIM: f32 = 0.55;
const LOCKSCREEN_DIM_BG: f32 = 0.0;
const LOCKSCREEN_DIM_ALL: bool = true;
const BLUR_SIZE: usize = 9;
const BLUR_DIV: u32 =
@ -174,14 +175,14 @@ fn homescreen_position_text(
fn homescreen_dim_area(x: i16, y: i16) -> bool {
y >= HOMESCREEN_DIM_START
&& (y > HOMESCREEN_DIM_START + 1
&& y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HIEGHT - 1)
&& y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT - 1)
&& x > HOMESCREEN_DIM_BORDER
&& x < WIDTH - HOMESCREEN_DIM_BORDER)
|| (y > HOMESCREEN_DIM_START
&& y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HIEGHT)
&& y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT)
&& x > HOMESCREEN_DIM_BORDER + 1
&& x < WIDTH - (HOMESCREEN_DIM_BORDER + 1))
|| ((HOMESCREEN_DIM_START..=(HOMESCREEN_DIM_START + HOMESCREEN_DIM_HIEGHT)).contains(&y)
|| ((HOMESCREEN_DIM_START..=(HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT)).contains(&y)
&& x > HOMESCREEN_DIM_BORDER + 2
&& x < WIDTH - (HOMESCREEN_DIM_BORDER + 2))
}
@ -197,7 +198,7 @@ fn homescreen_line_blurred(
let mut img_buffer = unsafe { get_buffer_16bpp((y & 0x1) as u16, false) };
for x in 0..HOMESCREEN_IMAGE_SIZE {
let c = if homescreen_dim_area(x, y) {
let c = if LOCKSCREEN_DIM_ALL {
let x = x as usize;
let coef = (65536_f32 * LOCKSCREEN_DIM) as u32;

View File

@ -3,12 +3,13 @@ use crate::ui::{
base::ComponentExt, AuxPageMsg, Component, Event, EventCtx, Never, Pad, PageMsg, Paginate,
},
display::{self, Color},
geometry::Rect,
geometry::{Insets, Rect},
};
use super::{theme, ScrollBar, Swipe, SwipeDirection};
const SCROLLBAR_HEIGHT: i16 = 32;
const SCROLLBAR_HEIGHT: i16 = 18;
const SCROLLBAR_BORDER: i16 = 4;
pub struct HorizontalPage<T> {
content: T,
@ -75,10 +76,11 @@ where
fn place(&mut self, bounds: Rect) -> Rect {
self.swipe.place(bounds);
let (content, scrollbar) = bounds.split_bottom(SCROLLBAR_HEIGHT);
let (content, scrollbar) = bounds.split_bottom(SCROLLBAR_HEIGHT + SCROLLBAR_BORDER);
self.pad.place(content);
self.content.place(content);
self.scrollbar.place(scrollbar);
self.scrollbar
.place(scrollbar.inset(Insets::bottom(SCROLLBAR_BORDER)));
self.scrollbar
.set_count_and_active_page(self.content.page_count(), 0);

View File

@ -215,20 +215,21 @@ impl Bip39Input {
{
// Confirm button.
self.button.enable(ctx);
self.button.set_stylesheet(ctx, theme::button_confirm());
self.button.set_stylesheet(ctx, theme::button_pin_confirm());
self.button
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CONFIRM)));
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_LIST_CHECK)));
} else {
// Auto-complete button.
self.button.enable(ctx);
self.button.set_stylesheet(ctx, theme::button_default());
self.button
.set_stylesheet(ctx, theme::button_pin_autocomplete());
self.button
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CLICK)));
}
} else {
// Disabled button.
self.button.disable(ctx);
self.button.set_stylesheet(ctx, theme::button_default());
self.button.set_stylesheet(ctx, theme::button_pin());
self.button.set_content(ctx, ButtonContent::Text(""));
}
}

View File

@ -43,11 +43,13 @@ where
Icon::new(theme::ICON_BACK),
Offset::new(30, 17),
)
.styled(theme::button_clear())
.styled(theme::button_reset())
.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),
}
}
@ -94,8 +96,10 @@ where
type Msg = MnemonicKeyboardMsg;
fn place(&mut self, bounds: Rect) -> Rect {
let grid =
Grid::new(bounds.inset(theme::borders()), 4, 3).with_spacing(theme::KEYBOARD_SPACING);
let (_, bounds) = bounds
.inset(theme::borders())
.split_bottom(4 * theme::MNEMONIC_BUTTON_HEIGHT + 3 * theme::KEYBOARD_SPACING);
let grid = Grid::new(bounds, 4, 3).with_spacing(theme::KEYBOARD_SPACING);
let back_area = grid.row_col(0, 0);
let input_area = grid.row_col(0, 1).union(grid.row_col(0, 3));

View File

@ -2,13 +2,10 @@ use crate::ui::{
component::{base::ComponentExt, Child, Component, Event, EventCtx, Never},
display,
display::toif::Icon,
geometry::{Grid, Insets, Offset, Rect},
geometry::{Grid, Offset, Rect},
model_tt::component::{
button::{Button, ButtonContent, ButtonMsg},
keyboard::common::{
paint_pending_marker, MultiTapKeyboard, TextBox, HEADER_HEIGHT, HEADER_PADDING_BOTTOM,
HEADER_PADDING_SIDE,
},
keyboard::common::{paint_pending_marker, MultiTapKeyboard, TextBox},
swipe::{Swipe, SwipeDirection},
theme, ScrollBar,
},
@ -41,6 +38,7 @@ const KEYBOARD: [[&str; KEY_COUNT]; PAGE_COUNT] = [
];
const MAX_LENGTH: usize = 50;
const INPUT_AREA_HEIGHT: i16 = ScrollBar::DOT_SIZE + 9;
impl PassphraseKeyboard {
pub fn new() -> Self {
@ -59,8 +57,9 @@ impl PassphraseKeyboard {
.initially_enabled(false)
.with_long_press(theme::ERASE_HOLD_DURATION)
.into_child(),
keys: KEYBOARD[STARTING_PAGE]
.map(|text| Child::new(Button::new(Self::key_content(text)))),
keys: KEYBOARD[STARTING_PAGE].map(|text| {
Child::new(Button::new(Self::key_content(text)).styled(theme::button_pin()))
}),
scrollbar: ScrollBar::horizontal(),
fade: false,
}
@ -152,14 +151,13 @@ impl Component for PassphraseKeyboard {
fn place(&mut self, bounds: Rect) -> Rect {
let bounds = bounds.inset(theme::borders());
let (input_area, key_grid_area) = bounds.split_top(HEADER_HEIGHT + HEADER_PADDING_BOTTOM);
let (input_area, key_grid_area) =
bounds.split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::BUTTON_SPACING);
let (input_area, scroll_area) =
input_area.split_bottom(ScrollBar::DOT_SIZE + theme::KEYBOARD_SPACING);
let (input_area, scroll_area) = input_area.split_bottom(INPUT_AREA_HEIGHT);
let (scroll_area, _) = scroll_area.split_top(ScrollBar::DOT_SIZE);
let input_area = input_area.inset(Insets::sides(HEADER_PADDING_SIDE));
let key_grid = Grid::new(key_grid_area, 4, 3).with_spacing(theme::KEYBOARD_SPACING);
let key_grid = Grid::new(key_grid_area, 4, 3).with_spacing(theme::BUTTON_SPACING);
let confirm_btn_area = key_grid.cell(11);
let back_btn_area = key_grid.cell(9);

View File

@ -59,8 +59,8 @@ where
T: AsRef<str>,
{
// Label position fine-tuning.
const MAJOR_OFF: Offset = Offset::y(-2);
const MINOR_OFF: Offset = Offset::y(-1);
const MAJOR_OFF: Offset = Offset::y(11);
const MINOR_OFF: Offset = Offset::y(11);
pub fn new(
major_prompt: T,
@ -165,14 +165,14 @@ where
// Prompts and PIN dots display.
let (header, keypad) = bounds
.inset(borders_no_top)
.split_top(theme::borders().top + HEADER_HEIGHT + HEADER_PADDING_BOTTOM);
.split_bottom(4 * theme::PIN_BUTTON_HEIGHT + 3 * theme::BUTTON_SPACING);
let prompt = header.inset(HEADER_PADDING);
// the inset -3 is a workaround for long text in "re-enter wipe code"
let major_area = prompt.translate(Self::MAJOR_OFF).inset(Insets::right(-3));
let minor_area = prompt.translate(Self::MINOR_OFF);
// Control buttons.
let grid = Grid::new(keypad, 4, 3).with_spacing(theme::KEYBOARD_SPACING);
let grid = Grid::new(keypad, 4, 3).with_spacing(theme::BUTTON_SPACING);
// Prompts and PIN dots display.
self.textbox_pad.place(header);

View File

@ -224,13 +224,13 @@ impl Slip39Input {
if self.final_word.is_some() {
// Confirm button.
self.button.enable(ctx);
self.button.set_stylesheet(ctx, theme::button_confirm());
self.button.set_stylesheet(ctx, theme::button_pin_confirm());
self.button
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_CONFIRM)));
.set_content(ctx, ButtonContent::Icon(Icon::new(theme::ICON_LIST_CHECK)));
} else {
// Disabled button.
self.button.disable(ctx);
self.button.set_stylesheet(ctx, theme::button_default());
self.button.set_stylesheet(ctx, theme::button_pin());
self.button.set_content(ctx, ButtonContent::Text(""));
}
}

View File

@ -22,7 +22,7 @@ pub enum SelectWordCountMsg {
impl SelectWordCount {
pub fn new() -> Self {
SelectWordCount {
button: LABELS.map(Button::with_text),
button: LABELS.map(|t| Button::with_text(t).styled(theme::button_pin())),
}
}
}
@ -31,7 +31,7 @@ impl Component for SelectWordCount {
type Msg = SelectWordCountMsg;
fn place(&mut self, bounds: Rect) -> Rect {
let (_, bounds) = bounds.split_bottom(theme::button_rows(2));
let (_, bounds) = bounds.split_bottom(2 * theme::BUTTON_HEIGHT + theme::BUTTON_SPACING);
let grid = Grid::new(bounds, 2, 6).with_spacing(theme::BUTTON_SPACING);
for (btn, (x, y)) in self.button.iter_mut().zip(CELLS) {
btn.place(grid.cells(GridCellSpan {

View File

@ -87,13 +87,12 @@ where
theme::CONTENT_BORDER,
));
let grid = Grid::new(button_area, 1, 3).with_spacing(theme::KEYBOARD_SPACING);
let grid = Grid::new(button_area, 1, 2).with_spacing(theme::KEYBOARD_SPACING);
self.input.place(input_area);
self.paragraphs.place(content_area);
self.paragraphs_pad.place(content_area);
self.info_button.place(grid.row_col(0, 0));
self.confirm_button
.place(grid.row_col(0, 1).union(grid.row_col(0, 2)));
self.confirm_button.place(grid.row_col(0, 1));
bounds
}

View File

@ -368,7 +368,7 @@ where
impl<T> ComponentMsgObj for AddressDetails<T>
where
T: ParagraphStrType,
T: ParagraphStrType + Clone,
{
fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result<Obj, Error> {
unreachable!();
@ -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())
@ -396,12 +399,12 @@ extern "C" fn new_confirm_action(n_args: usize, args: *const Obj, kwargs: *mut M
let mut paragraphs = ParagraphVecShort::new();
if !reverse {
paragraphs
.add(Paragraph::new(&theme::TEXT_BOLD, action))
.add(Paragraph::new(&theme::TEXT_DEMIBOLD, action))
.add(Paragraph::new(&theme::TEXT_NORMAL, description));
} else {
paragraphs
.add(Paragraph::new(&theme::TEXT_NORMAL, description))
.add(Paragraph::new(&theme::TEXT_BOLD, action));
.add(Paragraph::new(&theme::TEXT_DEMIBOLD, action));
}
paragraphs.into_paragraphs()
};
@ -440,7 +443,7 @@ fn confirm_blob(
extra: extra.unwrap_or_else(StrBuffer::empty),
data: data.try_into()?,
description_font: &theme::TEXT_NORMAL,
extra_font: &theme::TEXT_BOLD,
extra_font: &theme::TEXT_DEMIBOLD,
data_font: &theme::TEXT_MONO,
}
.into_paragraphs();
@ -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,
@ -499,19 +502,14 @@ extern "C" fn new_confirm_address(n_args: usize, args: *const Obj, kwargs: *mut
extra: extra.unwrap_or_else(StrBuffer::empty),
data: data.try_into()?,
description_font: &theme::TEXT_NORMAL,
extra_font: &theme::TEXT_BOLD,
extra_font: &theme::TEXT_DEMIBOLD,
data_font: &theme::TEXT_MONO,
}
.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_INFO_CIRCLE),
Icon::new(theme::ICON_CORNER_INFO),
Frame::left_aligned(
theme::label_title(),
title,
@ -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(),
@ -590,33 +588,26 @@ extern "C" fn new_confirm_reset_device(n_args: usize, args: *const Obj, kwargs:
let title: StrBuffer = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let button: StrBuffer = kwargs.get(Qstr::MP_QSTR_button)?.try_into()?;
let paragraphs = Paragraphs::new(Paragraph::new(
&theme::TEXT_NORMAL,
StrBuffer::from("By continuing you agree\nto Trezor Company's\nterms and conditions."),
));
let url = FormattedText::new(
theme::TEXT_NORMAL,
theme::FORMATTED,
"More info at {demibold}trezor.io/tos",
);
let paragraphs = Paragraphs::new([
Paragraph::new(
&theme::TEXT_NORMAL,
StrBuffer::from(
"By continuing you agree\nto Trezor Company's\nterms and conditions.\r",
),
),
Paragraph::new(&theme::TEXT_NORMAL, StrBuffer::from("More info at")),
Paragraph::new(&theme::TEXT_DEMIBOLD, StrBuffer::from("trezor.io/tos")),
]);
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(
theme::label_title(),
title,
Dialog::new(
(
GridPlaced::new(paragraphs)
.with_grid(3, 1)
.with_from_to((0, 0), (1, 0)),
GridPlaced::new(url).with_grid(3, 1).with_row_col(2, 0),
),
buttons,
),
Dialog::new(paragraphs, buttons),
)
.with_border(theme::borders()),
)?;
@ -635,7 +626,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(
@ -671,7 +662,7 @@ extern "C" fn new_show_address_details(n_args: usize, args: *const Obj, kwargs:
let obj = LayoutObj::new(
HorizontalPage::new(
FloatingButton::top_right_corner(Icon::new(theme::ICON_CANCEL_LARGER), ad),
FloatingButton::top_right_corner(Icon::new(theme::ICON_CORNER_CANCEL), ad),
theme::BG,
)
.with_swipe_right_to_go_back(),
@ -746,7 +737,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 +772,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 +823,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 +881,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);
@ -906,7 +897,7 @@ extern "C" fn new_confirm_fido(n_args: usize, args: *const Obj, kwargs: *mut Map
extern "C" fn new_show_warning(n_args: usize, args: *const Obj, kwargs: *mut Map) -> Obj {
let block = move |_args: &[Obj], kwargs: &Map| {
let icon = BlendedImage::new(
Icon::new(theme::IMAGE_BG_TRIANGLE),
Icon::new(theme::IMAGE_BG_OCTAGON),
Icon::new(theme::IMAGE_FG_WARN),
theme::WARN_COLOR,
theme::FG,
@ -952,15 +943,21 @@ extern "C" fn new_show_mismatch() -> Obj {
let url: StrBuffer = "trezor.io/support".into();
let button = "QUIT";
let icon = BlendedImage::single(Icon::new(theme::ICON_OCTA), theme::WARN_COLOR, theme::BG);
let icon = BlendedImage::new(
Icon::new(theme::IMAGE_BG_OCTAGON),
Icon::new(theme::IMAGE_FG_WARN),
theme::WARN_COLOR,
theme::FG,
theme::BG,
);
let obj = LayoutObj::new(
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)
@ -1095,9 +1092,9 @@ extern "C" fn new_confirm_coinjoin(n_args: usize, args: *const Obj, kwargs: *mut
let paragraphs = Paragraphs::new([
Paragraph::new(&theme::TEXT_NORMAL, "Maximum rounds:".into()),
Paragraph::new(&theme::TEXT_BOLD, max_rounds),
Paragraph::new(&theme::TEXT_MONO, max_rounds),
Paragraph::new(&theme::TEXT_NORMAL, "Maximum mining fee:".into()),
Paragraph::new(&theme::TEXT_BOLD, max_feerate),
Paragraph::new(&theme::TEXT_MONO, max_feerate),
]);
let obj = LayoutObj::new(Frame::left_aligned(
@ -1162,7 +1159,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(
@ -1295,7 +1292,7 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
let info_button: bool = kwargs.get_or(Qstr::MP_QSTR_info_button, false).unwrap();
let paragraphs = Paragraphs::new([
Paragraph::new(&theme::TEXT_BOLD, title).centered(),
Paragraph::new(&theme::TEXT_DEMIBOLD, title).centered(),
Paragraph::new(&theme::TEXT_NORMAL_OFF_WHITE, description).centered(),
])
.with_spacing(theme::RECOVERY_SPACING);
@ -1308,15 +1305,16 @@ extern "C" fn new_confirm_recovery(n_args: usize, args: *const Obj, kwargs: *mut
let obj = if info_button {
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())
@ -1334,11 +1332,15 @@ extern "C" fn new_select_word_count(n_args: usize, args: *const Obj, kwargs: *mu
let title = if dry_run {
"SEED CHECK"
} else {
"RECOVERY MODE"
"WALLET RECOVERY"
};
let paragraphs = Paragraphs::new(
Paragraph::new(&theme::TEXT_BOLD, StrBuffer::from("Number of words?")).centered(),
Paragraph::new(
&theme::TEXT_DEMIBOLD,
StrBuffer::from("Select number of words in your recovery seed."),
)
.centered(),
);
let obj = LayoutObj::new(
@ -1384,7 +1386,7 @@ extern "C" fn new_show_remaining_shares(n_args: usize, args: *const Obj, kwargs:
for page in iter {
let [title, description]: [StrBuffer; 2] = iter_into_array(page)?;
paragraphs
.add(Paragraph::new(&theme::TEXT_BOLD, title))
.add(Paragraph::new(&theme::TEXT_DEMIBOLD, title))
.add(Paragraph::new(&theme::TEXT_NORMAL, description).break_after());
}
@ -1915,7 +1917,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,

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More