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.
127 lines
3.7 KiB
127 lines
3.7 KiB
use crate::{
|
|
trezorhal::secbool::{secbool, sectrue},
|
|
ui::{
|
|
component::{Child, Component, Event, EventCtx, Label, Pad},
|
|
constant::{screen, WIDTH},
|
|
display::Icon,
|
|
geometry::{Insets, Point, Rect},
|
|
shape::Renderer,
|
|
},
|
|
};
|
|
|
|
use super::super::{
|
|
component::{Button, ButtonMsg::Clicked, IconText},
|
|
theme::bootloader::{
|
|
button_bld, button_bld_menu, text_title, BLD_BG, BUTTON_HEIGHT, CONTENT_PADDING,
|
|
CORNER_BUTTON_AREA, CORNER_BUTTON_TOUCH_EXPANSION, FIRE24, REFRESH24, TITLE_AREA, X32,
|
|
},
|
|
};
|
|
|
|
const BUTTON_AREA_START: i16 = 56;
|
|
const BUTTON_SPACING: i16 = 8;
|
|
|
|
#[repr(u32)]
|
|
#[derive(Copy, Clone, ToPrimitive)]
|
|
pub enum MenuMsg {
|
|
Close = 0xAABBCCDD,
|
|
Reboot = 0x11223344,
|
|
FactoryReset = 0x55667788,
|
|
}
|
|
|
|
pub struct Menu {
|
|
bg: Pad,
|
|
title: Child<Label<'static>>,
|
|
close: Child<Button>,
|
|
reboot: Child<Button>,
|
|
reset: Child<Button>,
|
|
}
|
|
|
|
impl Menu {
|
|
pub fn new(firmware_present: secbool) -> Self {
|
|
let content_reboot = IconText::new("REBOOT TREZOR", Icon::new(REFRESH24));
|
|
let content_reset = IconText::new("FACTORY RESET", Icon::new(FIRE24));
|
|
|
|
let mut instance = Self {
|
|
bg: Pad::with_background(BLD_BG),
|
|
title: Child::new(
|
|
Label::left_aligned("BOOTLOADER".into(), text_title(BLD_BG)).vertically_centered(),
|
|
),
|
|
close: Child::new(
|
|
Button::with_icon(Icon::new(X32))
|
|
.styled(button_bld_menu())
|
|
.with_expanded_touch_area(Insets::uniform(CORNER_BUTTON_TOUCH_EXPANSION)),
|
|
),
|
|
reboot: Child::new(
|
|
Button::with_icon_and_text(content_reboot)
|
|
.styled(button_bld())
|
|
.initially_enabled(sectrue == firmware_present),
|
|
),
|
|
reset: Child::new(Button::with_icon_and_text(content_reset).styled(button_bld())),
|
|
};
|
|
instance.bg.clear();
|
|
instance
|
|
}
|
|
}
|
|
|
|
impl Component for Menu {
|
|
type Msg = MenuMsg;
|
|
|
|
fn place(&mut self, bounds: Rect) -> Rect {
|
|
self.bg.place(screen());
|
|
self.title.place(TITLE_AREA);
|
|
self.close.place(CORNER_BUTTON_AREA);
|
|
self.reboot.place(Rect::new(
|
|
Point::new(CONTENT_PADDING, BUTTON_AREA_START),
|
|
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START + BUTTON_HEIGHT),
|
|
));
|
|
self.reset.place(Rect::new(
|
|
Point::new(
|
|
CONTENT_PADDING,
|
|
BUTTON_AREA_START + BUTTON_HEIGHT + BUTTON_SPACING,
|
|
),
|
|
Point::new(
|
|
WIDTH - CONTENT_PADDING,
|
|
BUTTON_AREA_START + 2 * BUTTON_HEIGHT + BUTTON_SPACING,
|
|
),
|
|
));
|
|
bounds
|
|
}
|
|
|
|
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
|
if let Some(Clicked) = self.close.event(ctx, event) {
|
|
return Some(Self::Msg::Close);
|
|
}
|
|
if let Some(Clicked) = self.reboot.event(ctx, event) {
|
|
return Some(Self::Msg::Reboot);
|
|
}
|
|
if let Some(Clicked) = self.reset.event(ctx, event) {
|
|
return Some(Self::Msg::FactoryReset);
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
fn paint(&mut self) {
|
|
self.bg.paint();
|
|
self.title.paint();
|
|
self.close.paint();
|
|
self.reboot.paint();
|
|
self.reset.paint();
|
|
}
|
|
|
|
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
|
self.bg.render(target);
|
|
self.title.render(target);
|
|
self.close.render(target);
|
|
self.reboot.render(target);
|
|
self.reset.render(target);
|
|
}
|
|
|
|
#[cfg(feature = "ui_bounds")]
|
|
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
|
self.close.bounds(sink);
|
|
self.reboot.bounds(sink);
|
|
self.reset.bounds(sink);
|
|
}
|
|
}
|