mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-19 14:08:11 +00:00
refactor(core/mercury): extract non-generic code from frame component
[no changelog]
This commit is contained in:
parent
f2bdd6e189
commit
873658104d
@ -45,11 +45,14 @@ impl<'a> Footer<'a> {
|
|||||||
const STYLE_INSTRUCTION: &'static TextStyle = &theme::TEXT_SUB_GREY;
|
const STYLE_INSTRUCTION: &'static TextStyle = &theme::TEXT_SUB_GREY;
|
||||||
const STYLE_DESCRIPTION: &'static TextStyle = &theme::TEXT_SUB_GREY_LIGHT;
|
const STYLE_DESCRIPTION: &'static TextStyle = &theme::TEXT_SUB_GREY_LIGHT;
|
||||||
|
|
||||||
pub fn new<T: Into<TString<'a>>>(instruction: T) -> Self {
|
pub fn new<T: Into<TString<'a>>>(
|
||||||
|
instruction: T,
|
||||||
|
description: Option<TString<'static>>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
area: Rect::zero(),
|
area: Rect::zero(),
|
||||||
instruction: instruction.into(),
|
instruction: instruction.into(),
|
||||||
content: None,
|
content: description.map(FooterContent::Description),
|
||||||
swipe_allow_down: false,
|
swipe_allow_down: false,
|
||||||
swipe_allow_up: false,
|
swipe_allow_up: false,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
@ -57,13 +60,6 @@ impl<'a> Footer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_description<T: Into<TString<'a>>>(self, description: T) -> Self {
|
|
||||||
Self {
|
|
||||||
content: Some(FooterContent::Description(description.into())),
|
|
||||||
..self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_page_counter(self, max_pages: u8) -> Self {
|
pub fn with_page_counter(self, max_pages: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
content: Some(FooterContent::PageCounter(PageCounter::new(max_pages))),
|
content: Some(FooterContent::PageCounter(PageCounter::new(max_pages))),
|
||||||
@ -110,16 +106,17 @@ impl<'a> Footer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_swipe_up(self) -> Self {
|
pub fn with_swipe(self, swipe_direction: SwipeDirection) -> Self {
|
||||||
Self {
|
match swipe_direction {
|
||||||
swipe_allow_up: true,
|
SwipeDirection::Up => Self {
|
||||||
..self
|
swipe_allow_up: true,
|
||||||
}
|
..self
|
||||||
}
|
},
|
||||||
pub fn with_swipe_down(self) -> Self {
|
SwipeDirection::Down => Self {
|
||||||
Self {
|
swipe_allow_down: true,
|
||||||
swipe_allow_down: true,
|
..self
|
||||||
..self
|
},
|
||||||
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::{theme, ButtonMsg, ButtonStyleSheet, CancelInfoConfirmMsg, Footer, Header};
|
use super::{theme, ButtonStyleSheet, CancelInfoConfirmMsg, Footer, Header};
|
||||||
use crate::{
|
use crate::{
|
||||||
strutil::TString,
|
strutil::TString,
|
||||||
ui::{
|
ui::{
|
||||||
@ -84,7 +84,6 @@ impl HorizontalSwipe {
|
|||||||
pub struct Frame<T> {
|
pub struct Frame<T> {
|
||||||
border: Insets,
|
border: Insets,
|
||||||
bounds: Rect,
|
bounds: Rect,
|
||||||
button_msg: CancelInfoConfirmMsg,
|
|
||||||
content: T,
|
content: T,
|
||||||
header: Header,
|
header: Header,
|
||||||
footer: Option<Footer<'static>>,
|
footer: Option<Footer<'static>>,
|
||||||
@ -106,7 +105,6 @@ where
|
|||||||
Self {
|
Self {
|
||||||
bounds: Rect::zero(),
|
bounds: Rect::zero(),
|
||||||
border: theme::borders(),
|
border: theme::borders(),
|
||||||
button_msg: CancelInfoConfirmMsg::Cancelled,
|
|
||||||
content,
|
content,
|
||||||
header: Header::new(alignment, title),
|
header: Header::new(alignment, title),
|
||||||
footer: None,
|
footer: None,
|
||||||
@ -145,8 +143,7 @@ where
|
|||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn with_button(mut self, icon: Icon, msg: CancelInfoConfirmMsg, enabled: bool) -> Self {
|
fn with_button(mut self, icon: Icon, msg: CancelInfoConfirmMsg, enabled: bool) -> Self {
|
||||||
self.header = self.header.with_button(icon, enabled);
|
self.header = self.header.with_button(icon, enabled, msg);
|
||||||
self.button_msg = msg;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,17 +186,13 @@ where
|
|||||||
instruction: TString<'static>,
|
instruction: TString<'static>,
|
||||||
description: Option<TString<'static>>,
|
description: Option<TString<'static>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut footer = Footer::new(instruction);
|
self.footer = Some(Footer::new(instruction, description));
|
||||||
if let Some(description_text) = description {
|
|
||||||
footer = footer.with_description(description_text);
|
|
||||||
}
|
|
||||||
self.footer = Some(footer);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn with_footer_counter(mut self, instruction: TString<'static>, max_value: u8) -> Self {
|
pub fn with_footer_counter(mut self, instruction: TString<'static>, max_value: u8) -> Self {
|
||||||
self.footer = Some(Footer::new(instruction).with_page_counter(max_value));
|
self.footer = Some(Footer::new(instruction, None).with_page_counter(max_value));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,8 +206,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_title(&mut self, ctx: &mut EventCtx, new_title: TString<'static>) {
|
pub fn update_title(&mut self, ctx: &mut EventCtx, new_title: TString<'static>) {
|
||||||
self.header.update_title(new_title);
|
self.header.update_title(ctx, new_title);
|
||||||
ctx.request_paint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_subtitle(
|
pub fn update_subtitle(
|
||||||
@ -223,8 +215,7 @@ where
|
|||||||
new_subtitle: TString<'static>,
|
new_subtitle: TString<'static>,
|
||||||
new_style: Option<TextStyle>,
|
new_style: Option<TextStyle>,
|
||||||
) {
|
) {
|
||||||
self.header.update_subtitle(new_subtitle, new_style);
|
self.header.update_subtitle(ctx, new_subtitle, new_style);
|
||||||
ctx.request_paint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_content<F, R>(&mut self, ctx: &mut EventCtx, update_fn: F) -> R
|
pub fn update_content<F, R>(&mut self, ctx: &mut EventCtx, update_fn: F) -> R
|
||||||
@ -244,11 +235,7 @@ where
|
|||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn with_swipe(mut self, dir: SwipeDirection, settings: SwipeSettings) -> Self {
|
pub fn with_swipe(mut self, dir: SwipeDirection, settings: SwipeSettings) -> Self {
|
||||||
self.footer = self.footer.map(|f| match dir {
|
self.footer = self.footer.map(|f| f.with_swipe(dir));
|
||||||
SwipeDirection::Up => f.with_swipe_up(),
|
|
||||||
SwipeDirection::Down => f.with_swipe_down(),
|
|
||||||
_ => f,
|
|
||||||
});
|
|
||||||
self.swipe = self.swipe.with_swipe(dir, settings);
|
self.swipe = self.swipe.with_swipe(dir, settings);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -275,21 +262,7 @@ where
|
|||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
self.bounds = bounds;
|
self.bounds = bounds;
|
||||||
|
let content_area = frame_place(&mut self.header, &mut self.footer, bounds);
|
||||||
let (mut header_area, mut content_area) = bounds.split_top(TITLE_HEIGHT);
|
|
||||||
content_area = content_area.inset(Insets::top(theme::SPACING));
|
|
||||||
header_area = header_area.inset(Insets::sides(theme::SPACING));
|
|
||||||
|
|
||||||
self.header.place(header_area);
|
|
||||||
|
|
||||||
if let Some(footer) = &mut self.footer {
|
|
||||||
// FIXME: spacer at the bottom might be applied also for usage without footer
|
|
||||||
// but not for VerticalMenu
|
|
||||||
content_area = content_area.inset(Insets::bottom(theme::SPACING));
|
|
||||||
let (remaining, footer_area) = content_area.split_bottom(footer.height());
|
|
||||||
footer.place(footer_area);
|
|
||||||
content_area = remaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.content.place(content_area);
|
self.content.place(content_area);
|
||||||
|
|
||||||
@ -297,9 +270,17 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||||
self.horizontal_swipe.event(event, self.swipe);
|
if let Some(value) = frame_event(
|
||||||
|
&mut self.horizontal_swipe,
|
||||||
|
self.swipe,
|
||||||
|
&mut self.header,
|
||||||
|
&mut self.footer,
|
||||||
|
ctx,
|
||||||
|
event,
|
||||||
|
) {
|
||||||
|
return Some(FrameMsg::Button(value));
|
||||||
|
}
|
||||||
|
|
||||||
self.footer.event(ctx, event);
|
|
||||||
let msg = self.content.event(ctx, event).map(FrameMsg::Content);
|
let msg = self.content.event(ctx, event).map(FrameMsg::Content);
|
||||||
if let Some(count) = ctx.page_count() {
|
if let Some(count) = ctx.page_count() {
|
||||||
self.internal_page_cnt = count;
|
self.internal_page_cnt = count;
|
||||||
@ -308,9 +289,7 @@ where
|
|||||||
if msg.is_some() {
|
if msg.is_some() {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
if let Some(ButtonMsg::Clicked) = self.header.event(ctx, event) {
|
|
||||||
return Some(FrameMsg::Button(self.button_msg));
|
|
||||||
}
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,6 +307,37 @@ where
|
|||||||
.render_swipe_cover(target, self.bounds);
|
.render_swipe_cover(target, self.bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn frame_event(
|
||||||
|
horizontal_swipe: &mut HorizontalSwipe,
|
||||||
|
swipe_config: SwipeConfig,
|
||||||
|
header: &mut Header,
|
||||||
|
footer: &mut Option<Footer>,
|
||||||
|
ctx: &mut EventCtx,
|
||||||
|
event: Event,
|
||||||
|
) -> Option<CancelInfoConfirmMsg> {
|
||||||
|
horizontal_swipe.event(event, swipe_config);
|
||||||
|
|
||||||
|
footer.event(ctx, event);
|
||||||
|
|
||||||
|
header.event(ctx, event)
|
||||||
|
}
|
||||||
|
fn frame_place(header: &mut Header, footer: &mut Option<Footer>, bounds: Rect) -> Rect {
|
||||||
|
let (mut header_area, mut content_area) = bounds.split_top(TITLE_HEIGHT);
|
||||||
|
content_area = content_area.inset(Insets::top(theme::SPACING));
|
||||||
|
header_area = header_area.inset(Insets::sides(theme::SPACING));
|
||||||
|
|
||||||
|
header.place(header_area);
|
||||||
|
|
||||||
|
if let Some(footer) = footer {
|
||||||
|
// FIXME: spacer at the bottom might be applied also for usage without footer
|
||||||
|
// but not for VerticalMenu
|
||||||
|
content_area = content_area.inset(Insets::bottom(theme::SPACING));
|
||||||
|
let (remaining, footer_area) = content_area.split_bottom(footer.height());
|
||||||
|
footer.place(footer_area);
|
||||||
|
content_area = remaining;
|
||||||
|
}
|
||||||
|
content_area
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "micropython")]
|
#[cfg(feature = "micropython")]
|
||||||
impl<T> crate::ui::flow::Swipable for Frame<T> {
|
impl<T> crate::ui::flow::Swipable for Frame<T> {
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
geometry::{Alignment, Alignment2D, Insets, Offset, Rect},
|
geometry::{Alignment, Alignment2D, Insets, Offset, Rect},
|
||||||
lerp::Lerp,
|
lerp::Lerp,
|
||||||
model_mercury::{
|
model_mercury::{
|
||||||
component::{Button, ButtonMsg, ButtonStyleSheet},
|
component::{Button, ButtonMsg, ButtonStyleSheet, CancelInfoConfirmMsg},
|
||||||
theme,
|
theme,
|
||||||
theme::TITLE_HEIGHT,
|
theme::TITLE_HEIGHT,
|
||||||
},
|
},
|
||||||
@ -71,6 +71,7 @@ pub struct Header {
|
|||||||
icon: Option<Icon>,
|
icon: Option<Icon>,
|
||||||
color: Option<Color>,
|
color: Option<Color>,
|
||||||
title_style: TextStyle,
|
title_style: TextStyle,
|
||||||
|
button_msg: CancelInfoConfirmMsg,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Header {
|
impl Header {
|
||||||
@ -84,6 +85,7 @@ impl Header {
|
|||||||
icon: None,
|
icon: None,
|
||||||
color: None,
|
color: None,
|
||||||
title_style: theme::label_title_main(),
|
title_style: theme::label_title_main(),
|
||||||
|
button_msg: CancelInfoConfirmMsg::Cancelled,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
@ -107,12 +109,14 @@ impl Header {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn update_title(&mut self, title: TString<'static>) {
|
pub fn update_title(&mut self, ctx: &mut EventCtx, title: TString<'static>) {
|
||||||
self.title.set_text(title);
|
self.title.set_text(title);
|
||||||
|
ctx.request_paint();
|
||||||
}
|
}
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn update_subtitle(
|
pub fn update_subtitle(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
ctx: &mut EventCtx,
|
||||||
new_subtitle: TString<'static>,
|
new_subtitle: TString<'static>,
|
||||||
new_style: Option<TextStyle>,
|
new_style: Option<TextStyle>,
|
||||||
) {
|
) {
|
||||||
@ -126,10 +130,11 @@ impl Header {
|
|||||||
self.subtitle = Some(Label::new(new_subtitle, self.title.alignment(), style));
|
self.subtitle = Some(Label::new(new_subtitle, self.title.alignment(), style));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ctx.request_paint();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn with_button(mut self, icon: Icon, enabled: bool) -> Self {
|
pub fn with_button(mut self, icon: Icon, enabled: bool, msg: CancelInfoConfirmMsg) -> Self {
|
||||||
let touch_area = Insets::uniform(BUTTON_EXPAND_BORDER);
|
let touch_area = Insets::uniform(BUTTON_EXPAND_BORDER);
|
||||||
self.button = Some(
|
self.button = Some(
|
||||||
Button::with_icon(icon)
|
Button::with_icon(icon)
|
||||||
@ -137,6 +142,7 @@ impl Header {
|
|||||||
.initially_enabled(enabled)
|
.initially_enabled(enabled)
|
||||||
.styled(theme::button_default()),
|
.styled(theme::button_default()),
|
||||||
);
|
);
|
||||||
|
self.button_msg = msg;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
@ -160,7 +166,7 @@ impl Header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Header {
|
impl Component for Header {
|
||||||
type Msg = ButtonMsg;
|
type Msg = CancelInfoConfirmMsg;
|
||||||
|
|
||||||
fn place(&mut self, bounds: Rect) -> Rect {
|
fn place(&mut self, bounds: Rect) -> Rect {
|
||||||
let header_area = if let Some(b) = &mut self.button {
|
let header_area = if let Some(b) = &mut self.button {
|
||||||
@ -201,7 +207,11 @@ impl Component for Header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.button.event(ctx, event)
|
if let Some(ButtonMsg::Clicked) = self.button.event(ctx, event) {
|
||||||
|
return Some(self.button_msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&mut self) {
|
fn paint(&mut self) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::{theme, Footer};
|
||||||
use crate::{
|
use crate::{
|
||||||
strutil::{ShortString, TString},
|
strutil::{ShortString, TString},
|
||||||
translations::TR,
|
translations::TR,
|
||||||
@ -11,8 +12,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{theme, Footer};
|
|
||||||
|
|
||||||
pub enum NumberInputSliderDialogMsg {
|
pub enum NumberInputSliderDialogMsg {
|
||||||
Changed(u16),
|
Changed(u16),
|
||||||
}
|
}
|
||||||
@ -32,8 +31,10 @@ impl NumberInputSliderDialog {
|
|||||||
Self {
|
Self {
|
||||||
area: Rect::zero(),
|
area: Rect::zero(),
|
||||||
input: NumberInputSlider::new(min, max, init_value).into_child(),
|
input: NumberInputSlider::new(min, max, init_value).into_child(),
|
||||||
footer: Footer::new::<TString<'static>>(TR::instructions__swipe_horizontally.into())
|
footer: Footer::new::<TString<'static>>(
|
||||||
.with_description::<TString<'static>>(TR::setting__adjust.into()),
|
TR::instructions__swipe_horizontally.into(),
|
||||||
|
Some(TR::setting__adjust.into()),
|
||||||
|
),
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
val: init_value,
|
val: init_value,
|
||||||
|
Loading…
Reference in New Issue
Block a user