You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/rust/src/ui/model_tt/bootloader/confirm.rs

197 lines
6.2 KiB

use crate::ui::{
component::{
text::paragraphs::{ParagraphVecShort, Paragraphs},
Child, Component, ComponentExt, Event, EventCtx, Label, Pad,
},
constant,
constant::screen,
display::{Color, Icon},
geometry::{Alignment, Insets, Offset, Point, Rect, TOP_CENTER},
model_tt::{
bootloader::theme::{
button_bld_menu, BUTTON_AREA_START, CLOSE, CONTENT_PADDING, CORNER_BUTTON_AREA,
INFO_SMALL, TEXT_TITLE, TITLE_AREA,
},
component::{Button, ButtonMsg::Clicked},
constant::WIDTH,
theme::WHITE,
},
};
#[derive(Copy, Clone, ToPrimitive)]
pub enum ConfirmMsg {
Cancel = 1,
Confirm = 2,
}
pub struct Confirm<'a> {
bg: Pad,
content_pad: Pad,
bg_color: Color,
icon: Option<Icon>,
title: Option<Child<Label<&'static str>>>,
message: Child<Paragraphs<ParagraphVecShort<&'a str>>>,
left: Child<Button<&'static str>>,
right: Child<Button<&'static str>>,
info_button: Option<Button<&'static str>>,
close_button: Option<Button<&'static str>>,
info_title: Option<Child<Label<&'static str>>>,
info_text: Option<Paragraphs<ParagraphVecShort<&'a str>>>,
show_info: bool,
confirm_left: bool,
}
impl<'a> Confirm<'a> {
pub fn new(
bg_color: Color,
icon: Option<Icon>,
left: Button<&'static str>,
right: Button<&'static str>,
confirm_left: bool,
confirm: (Option<&'static str>, Paragraphs<ParagraphVecShort<&'a str>>),
info: Option<(&'static str, Paragraphs<ParagraphVecShort<&'a str>>)>,
) -> Self {
let mut instance = Self {
bg: Pad::with_background(bg_color),
content_pad: Pad::with_background(bg_color),
bg_color,
icon,
message: Child::new(confirm.1),
left: Child::new(left),
right: Child::new(right),
close_button: None,
info_button: None,
info_title: None,
info_text: None,
confirm_left,
show_info: false,
title: confirm
.0
.map(|title| Child::new(Label::new(title, Alignment::Start, TEXT_TITLE))),
};
if let Some((title, text)) = info {
instance.info_title = Some(Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)));
instance.info_text = Some(text);
instance.info_button = Some(
Button::with_icon(Icon::new(INFO_SMALL))
.styled(button_bld_menu())
.with_expanded_touch_area(Insets::uniform(13)),
);
instance.close_button = Some(
Button::with_icon(Icon::new(CLOSE))
.styled(button_bld_menu())
.with_expanded_touch_area(Insets::uniform(13)),
);
}
instance.bg.clear();
instance
}
}
impl<'a> Component for Confirm<'a> {
type Msg = ConfirmMsg;
fn place(&mut self, bounds: Rect) -> Rect {
self.bg.place(constant::screen());
self.content_pad.place(Rect::new(
Point::zero(),
Point::new(WIDTH, BUTTON_AREA_START),
));
let icon_height = if let Some(icon) = self.icon {
icon.toif.height()
} else {
0
};
self.message.place(Rect::new(
Point::new(CONTENT_PADDING, 32 + icon_height),
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
));
let button_size = Offset::new(106, 38);
self.left.place(Rect::from_top_left_and_size(
Point::new(CONTENT_PADDING, BUTTON_AREA_START),
button_size,
));
self.right.place(Rect::from_top_left_and_size(
Point::new(124, BUTTON_AREA_START),
button_size,
));
self.info_button.place(CORNER_BUTTON_AREA);
self.close_button.place(CORNER_BUTTON_AREA);
self.info_title.place(TITLE_AREA);
self.title.place(TITLE_AREA);
self.info_text.place(Rect::new(
Point::new(CONTENT_PADDING, TITLE_AREA.y1),
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
));
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
if self.show_info {
if let Some(Clicked) = self.close_button.event(ctx, event) {
self.show_info = false;
self.content_pad.clear();
self.title.request_complete_repaint(ctx);
self.message.request_complete_repaint(ctx);
return None;
}
} else if let Some(Clicked) = self.info_button.event(ctx, event) {
self.show_info = true;
self.info_text.request_complete_repaint(ctx);
self.info_title.request_complete_repaint(ctx);
self.content_pad.clear();
return None;
}
if let Some(Clicked) = self.left.event(ctx, event) {
return if self.confirm_left {
Some(Self::Msg::Confirm)
} else {
Some(Self::Msg::Cancel)
};
};
if let Some(Clicked) = self.right.event(ctx, event) {
return if self.confirm_left {
Some(Self::Msg::Cancel)
} else {
Some(Self::Msg::Confirm)
};
};
None
}
fn paint(&mut self) {
self.bg.paint();
self.content_pad.paint();
if self.show_info {
self.close_button.paint();
self.info_title.paint();
self.info_text.paint();
self.left.paint();
self.right.paint();
} else {
self.info_button.paint();
self.title.paint();
self.message.paint();
self.left.paint();
self.right.paint();
if let Some(icon) = self.icon {
icon.draw(
Point::new(screen().center().x, 32),
TOP_CENTER,
WHITE,
self.bg_color,
);
}
}
}
#[cfg(feature = "ui_bounds")]
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
self.left.bounds(sink);
self.right.bounds(sink);
}
}