Skip to content

Commit 05749db

Browse files
committed
chore(core/eckhart): extend header buttons
- use header builder functions where possible - update fixtures [no changelog]
1 parent 5cf27b5 commit 05749db

File tree

7 files changed

+6765
-6769
lines changed

7 files changed

+6765
-6769
lines changed

core/embed/rust/src/ui/layout_eckhart/firmware/header.rs

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,10 @@ use super::{
1313
constant, theme,
1414
};
1515

16-
const BUTTON_EXPAND_BORDER: i16 = 32;
17-
1816
/// Component for the header of a screen. Eckhart UI shows the title (can be two
1917
/// lines), optional icon button on the left, and optional icon button
2018
/// (typically for menu) on the right.
2119
pub struct Header {
22-
area: Rect,
2320
title: Label<'static>,
2421
/// button in the top-right corner
2522
right_button: Option<Button>,
@@ -30,6 +27,7 @@ pub struct Header {
3027
/// icon in the top-left corner (used instead of left button)
3128
icon: Option<Icon>,
3229
icon_color: Option<Color>,
30+
icon_area: Rect,
3331
/// Battery status indicator
3432
fuel_gauge: Option<FuelGauge>,
3533
}
@@ -43,19 +41,18 @@ pub enum HeaderMsg {
4341

4442
impl Header {
4543
pub const HEADER_HEIGHT: i16 = theme::HEADER_HEIGHT; // [px]
46-
pub const HEADER_BUTTON_WIDTH: i16 = 56; // [px]
47-
pub const HEADER_INSETS: Insets = Insets::sides(24); // [px]
44+
const BUTTON_TOUCH_EXPAND: Insets = Insets::sides(32); // [px]
4845

4946
pub const fn new(title: TString<'static>) -> Self {
5047
Self {
51-
area: Rect::zero(),
5248
title: Label::left_aligned(title, theme::label_title_main()).vertically_centered(),
5349
right_button: None,
5450
left_button: None,
5551
right_button_msg: HeaderMsg::Cancelled,
5652
left_button_msg: HeaderMsg::Cancelled,
5753
icon: None,
5854
icon_color: None,
55+
icon_area: Rect::zero(),
5956
fuel_gauge: Some(FuelGauge::on_charging_change()),
6057
}
6158
}
@@ -69,9 +66,12 @@ impl Header {
6966
#[inline(never)]
7067
pub fn with_right_button(self, button: Button, msg: HeaderMsg) -> Self {
7168
debug_assert!(matches!(button.content(), ButtonContent::Icon(_)));
72-
let touch_area = Insets::uniform(BUTTON_EXPAND_BORDER);
7369
Self {
74-
right_button: Some(button.with_expanded_touch_area(touch_area)),
70+
right_button: Some(
71+
button
72+
.with_expanded_touch_area(Self::BUTTON_TOUCH_EXPAND)
73+
.with_radius(12),
74+
),
7575
right_button_msg: msg,
7676
..self
7777
}
@@ -80,10 +80,13 @@ impl Header {
8080
#[inline(never)]
8181
pub fn with_left_button(self, button: Button, msg: HeaderMsg) -> Self {
8282
debug_assert!(matches!(button.content(), ButtonContent::Icon(_)));
83-
let touch_area = Insets::uniform(BUTTON_EXPAND_BORDER);
8483
Self {
8584
icon: None,
86-
left_button: Some(button.with_expanded_touch_area(touch_area)),
85+
left_button: Some(
86+
button
87+
.with_expanded_touch_area(Self::BUTTON_TOUCH_EXPAND)
88+
.with_radius(12),
89+
),
8790
left_button_msg: msg,
8891
..self
8992
}
@@ -126,20 +129,35 @@ impl Header {
126129
ctx.request_paint();
127130
}
128131

132+
/// Calculates the width needed for the right button
133+
fn right_button_width(&self) -> i16 {
134+
if let Some(b) = &self.right_button {
135+
match b.content() {
136+
ButtonContent::Icon(icon) => icon.toif.width() + 2 * theme::PADDING,
137+
// We do not expect any other ButtonContent as the right button of the Header
138+
_ => unreachable!(),
139+
}
140+
} else {
141+
// Title must have a default padding from the right side
142+
theme::PADDING
143+
}
144+
}
145+
129146
/// Calculates the width needed for the left icon, be it a button with icon
130147
/// or just icon
131-
fn left_icon_width(&self) -> i16 {
132-
let margin_right: i16 = 16; // [px]
148+
fn left_object_width(&self) -> i16 {
149+
const ICON_MARGIN_RIGHT: i16 = 16; // [px]
133150
if let Some(b) = &self.left_button {
134151
match b.content() {
135-
ButtonContent::Icon(icon) => icon.toif.width() + margin_right,
152+
ButtonContent::Icon(icon) => icon.toif.width() + 2 * theme::PADDING,
136153
// We do not expect any other ButtonContent as the left button of the Header
137154
_ => unreachable!(),
138155
}
139156
} else if let Some(icon) = self.icon {
140-
icon.toif.width() + margin_right
157+
theme::PADDING + icon.toif.width() + ICON_MARGIN_RIGHT
141158
} else {
142-
0
159+
// Title must have a default padding from the left side
160+
theme::PADDING
143161
}
144162
}
145163
}
@@ -148,31 +166,24 @@ impl Component for Header {
148166
type Msg = HeaderMsg;
149167

150168
fn place(&mut self, bounds: Rect) -> Rect {
151-
debug_assert_eq!(bounds.width(), constant::screen().width());
169+
debug_assert_eq!(bounds.width(), constant::SCREEN.width());
152170
debug_assert_eq!(bounds.height(), Self::HEADER_HEIGHT);
153171

154-
let bounds = bounds.inset(Self::HEADER_INSETS);
155-
let rest = if let Some(b) = &mut self.right_button {
156-
let (rest, right_button_area) = bounds.split_right(Self::HEADER_BUTTON_WIDTH);
157-
b.place(right_button_area);
158-
rest
159-
} else {
160-
bounds
161-
};
162-
163-
let icon_width = self.left_icon_width();
164-
let (left_button_area, title_area) = rest.split_left(icon_width);
172+
let (rest, right_button_area) = bounds.split_right(self.right_button_width());
173+
self.icon_area = rest.inset(Insets::left(theme::PADDING));
174+
let (left_object_area, title_area) = rest.split_left(self.left_object_width());
165175

166-
self.left_button.place(left_button_area);
176+
self.left_button.place(left_object_area);
167177
self.title.place(title_area);
168-
self.fuel_gauge.place(title_area.union(left_button_area));
178+
self.fuel_gauge.place(self.icon_area);
179+
self.right_button.place(right_button_area);
180+
169181
if let Some(fuel_gauge) = &mut self.fuel_gauge {
170182
// Force update the fuel gauge state, so it is up-to-date
171183
// necessary e.g. for the first DeviceMenu Submenu re-entry
172184
fuel_gauge.update_pm_state();
173185
}
174186

175-
self.area = bounds;
176187
bounds
177188
}
178189

@@ -200,7 +211,7 @@ impl Component for Header {
200211
} else {
201212
self.left_button.render(target);
202213
if let Some(icon) = self.icon {
203-
shape::ToifImage::new(self.area.left_center(), icon.toif)
214+
shape::ToifImage::new(self.icon_area.left_center(), icon.toif)
204215
.with_fg(self.icon_color.unwrap_or(theme::GREY_LIGHT))
205216
.with_align(Alignment2D::CENTER_LEFT)
206217
.render(target);

core/embed/rust/src/ui/layout_eckhart/firmware/hold_to_confirm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ impl HoldToConfirmAnim {
178178
// FIXME: vert_center is precisely aligned with the `Header` title (which uses
179179
// `Label`) but this solution might break with `Header` changes
180180
let text_offset = Offset::new(
181-
Header::HEADER_INSETS.left,
181+
theme::PADDING,
182182
font.vert_center(0, Header::HEADER_HEIGHT - 1, "A"),
183183
);
184184
let text_pos = header_pad.top_left() + text_offset;

core/embed/rust/src/ui/layout_eckhart/flow/confirm_reset.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{
1818
use super::super::{
1919
component::Button,
2020
firmware::{
21-
ActionBar, Header, HeaderMsg, Hint, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
21+
ActionBar, Header, Hint, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
2222
VerticalMenuScreen, VerticalMenuScreenMsg,
2323
},
2424
theme::{self, gradient::Gradient},
@@ -90,10 +90,7 @@ pub fn new_confirm_reset(recovery: bool) -> Result<SwipeFlow, error::Error> {
9090
let content_menu = VerticalMenuScreen::new(VerticalMenu::<ShortMenuVec>::empty().with_item(
9191
Button::new_menu_item(TR::buttons__cancel.into(), theme::menu_item_title_orange()),
9292
))
93-
.with_header(
94-
Header::new(title)
95-
.with_right_button(Button::with_icon(theme::ICON_CROSS), HeaderMsg::Cancelled),
96-
)
93+
.with_header(Header::new(title).with_close_button())
9794
.map(|msg| match msg {
9895
VerticalMenuScreenMsg::Selected(i) => Some(FlowMsg::Choice(i)),
9996
VerticalMenuScreenMsg::Close => Some(FlowMsg::Cancelled),

core/embed/rust/src/ui/layout_eckhart/flow/prompt_backup.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{
1818
use super::super::{
1919
component::Button,
2020
firmware::{
21-
ActionBar, Header, HeaderMsg, Hint, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
21+
ActionBar, Header, Hint, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
2222
VerticalMenuScreen, VerticalMenuScreenMsg,
2323
},
2424
theme::{self, gradient::Gradient},
@@ -79,10 +79,7 @@ pub fn new_prompt_backup() -> Result<SwipeFlow, error::Error> {
7979
theme::menu_item_title_orange(),
8080
),
8181
))
82-
.with_header(
83-
Header::new(title)
84-
.with_right_button(Button::with_icon(theme::ICON_CROSS), HeaderMsg::Cancelled),
85-
)
82+
.with_header(Header::new(title).with_close_button())
8683
.map(|msg| match msg {
8784
VerticalMenuScreenMsg::Selected(i) => Some(FlowMsg::Choice(i)),
8885
VerticalMenuScreenMsg::Close => Some(FlowMsg::Cancelled),

core/embed/rust/src/ui/layout_eckhart/flow/receive.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ use heapless::Vec;
2424
use super::super::{
2525
component::Button,
2626
firmware::{
27-
ActionBar, Header, HeaderMsg, Hint, QrScreen, ShortMenuVec, TextScreen, TextScreenMsg,
28-
VerticalMenu, VerticalMenuScreen, VerticalMenuScreenMsg,
27+
ActionBar, Header, Hint, QrScreen, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
28+
VerticalMenuScreen, VerticalMenuScreenMsg,
2929
},
3030
theme::{self, gradient::Gradient},
3131
};
@@ -159,10 +159,7 @@ pub fn new_receive(
159159
theme::menu_item_title_orange(),
160160
)),
161161
)
162-
.with_header(
163-
Header::new(title)
164-
.with_right_button(Button::with_icon(theme::ICON_CROSS), HeaderMsg::Cancelled),
165-
)
162+
.with_header(Header::new(title).with_close_button())
166163
.map(|msg| match msg {
167164
VerticalMenuScreenMsg::Selected(i) => Some(FlowMsg::Choice(i)),
168165
VerticalMenuScreenMsg::Close => Some(FlowMsg::Cancelled),
@@ -214,10 +211,7 @@ pub fn new_receive(
214211
para.into_paragraphs()
215212
.with_placement(LinearPlacement::vertical()),
216213
)
217-
.with_header(
218-
Header::new(TR::address_details__account_info.into())
219-
.with_right_button(Button::with_icon(theme::ICON_CROSS), HeaderMsg::Cancelled),
220-
)
214+
.with_header(Header::new(TR::address_details__account_info.into()).with_close_button())
221215
.map(|_| Some(FlowMsg::Cancelled));
222216

223217
// Cancel

core/embed/rust/src/ui/layout_eckhart/flow/show_danger.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
use super::super::{
2020
component::Button,
2121
firmware::{
22-
ActionBar, Header, HeaderMsg, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
22+
ActionBar, Header, ShortMenuVec, TextScreen, TextScreenMsg, VerticalMenu,
2323
VerticalMenuScreen, VerticalMenuScreenMsg,
2424
},
2525
theme,
@@ -98,10 +98,7 @@ pub fn new_show_danger(
9898
theme::menu_item_title_orange(),
9999
)),
100100
)
101-
.with_header(
102-
Header::new(menu_title.unwrap_or("".into()))
103-
.with_right_button(Button::with_icon(theme::ICON_CROSS), HeaderMsg::Cancelled),
104-
)
101+
.with_header(Header::new(menu_title.unwrap_or(TString::empty())).with_close_button())
105102
.map(|msg| match msg {
106103
VerticalMenuScreenMsg::Selected(i) => Some(FlowMsg::Choice(i)),
107104
VerticalMenuScreenMsg::Close => Some(FlowMsg::Cancelled),

0 commit comments

Comments
 (0)