parent
e928568339
commit
531511407b
After Width: | Height: | Size: 8.0 KiB |
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,47 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
display::{self, Font},
|
||||
geometry::{Offset, Rect},
|
||||
};
|
||||
|
||||
use super::theme::{BLD_BG, BLD_FG};
|
||||
|
||||
pub struct Connect {
|
||||
bg: Pad,
|
||||
message: &'static str,
|
||||
}
|
||||
|
||||
impl Connect {
|
||||
pub fn new(message: &'static str) -> Self {
|
||||
Self {
|
||||
bg: Pad::with_background(BLD_BG).with_clear(),
|
||||
message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Connect {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(bounds);
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let font = Font::NORMAL;
|
||||
|
||||
self.bg.paint();
|
||||
display::text_center(
|
||||
self.bg.area.center() + Offset::y(font.text_height() / 2),
|
||||
self.message,
|
||||
font,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,46 +1,152 @@
|
||||
#[cfg(feature = "ui_debug")]
|
||||
use crate::trace::{Trace, Tracer};
|
||||
use crate::ui::{
|
||||
component::{Child, Component, Event, EventCtx, Never, Pad},
|
||||
geometry::{Point, Rect},
|
||||
component::{Child, Component, Event, EventCtx, Pad},
|
||||
constant::screen,
|
||||
display,
|
||||
display::{Font, Icon},
|
||||
geometry::{Offset, Point, Rect, CENTER},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
bootloader::{theme::BLD_BG, title::Title},
|
||||
constant::{HEIGHT, WIDTH},
|
||||
use super::{
|
||||
super::component::{Choice, ChoiceFactory, ChoicePage},
|
||||
theme::{BLD_BG, BLD_FG, ICON_EXIT, ICON_REDO, ICON_TRASH},
|
||||
ReturnToC,
|
||||
};
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum MenuMsg {
|
||||
Close = 1,
|
||||
Reboot = 2,
|
||||
FactoryReset = 3,
|
||||
}
|
||||
impl ReturnToC for MenuMsg {
|
||||
fn return_to_c(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
const CHOICE_LENGTH: usize = 3;
|
||||
const SCREEN_CENTER: Point = screen().center();
|
||||
|
||||
pub struct MenuChoice {
|
||||
first_line: &'static str,
|
||||
second_line: &'static str,
|
||||
icon: Icon,
|
||||
}
|
||||
|
||||
impl MenuChoice {
|
||||
pub fn new(first_line: &'static str, second_line: &'static str, icon: Icon) -> Self {
|
||||
Self {
|
||||
first_line,
|
||||
second_line,
|
||||
icon,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Choice<&'static str> for MenuChoice {
|
||||
fn paint_center(&self, _area: Rect, _inverse: bool) {
|
||||
// Icon on top and two lines of text below
|
||||
self.icon
|
||||
.draw(SCREEN_CENTER + Offset::y(-20), CENTER, BLD_FG, BLD_BG);
|
||||
|
||||
display::text_center(SCREEN_CENTER, self.first_line, Font::NORMAL, BLD_FG, BLD_BG);
|
||||
display::text_center(
|
||||
SCREEN_CENTER + Offset::y(10),
|
||||
self.second_line,
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl Trace for MenuChoice {
|
||||
fn trace(&self, t: &mut dyn Tracer) {
|
||||
t.component("MenuChoice");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MenuChoiceFactory;
|
||||
|
||||
impl MenuChoiceFactory {
|
||||
const CHOICES: [(&'static str, &'static str, Icon); CHOICE_LENGTH] = [
|
||||
("Factory", "reset", ICON_TRASH),
|
||||
("Reboot", "Trezor", ICON_REDO),
|
||||
("Exit", "menu", ICON_EXIT),
|
||||
];
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl ChoiceFactory<&'static str> for MenuChoiceFactory {
|
||||
type Action = MenuMsg;
|
||||
type Item = MenuChoice;
|
||||
|
||||
fn count(&self) -> usize {
|
||||
CHOICE_LENGTH
|
||||
}
|
||||
|
||||
fn get(&self, choice_index: usize) -> (Self::Item, Self::Action) {
|
||||
let choice_item = MenuChoice::new(
|
||||
Self::CHOICES[choice_index].0,
|
||||
Self::CHOICES[choice_index].1,
|
||||
Self::CHOICES[choice_index].2,
|
||||
);
|
||||
let action = match choice_index {
|
||||
0 => MenuMsg::FactoryReset,
|
||||
1 => MenuMsg::Reboot,
|
||||
2 => MenuMsg::Close,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
(choice_item, action)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Menu {
|
||||
bg: Pad,
|
||||
title: Child<Title>,
|
||||
pad: Pad,
|
||||
choice_page: Child<ChoicePage<MenuChoiceFactory, &'static str, MenuMsg>>,
|
||||
}
|
||||
|
||||
impl Menu {
|
||||
pub fn new(bld_version: &'static str) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
title: Child::new(Title::new(bld_version)),
|
||||
};
|
||||
instance.bg.clear();
|
||||
instance
|
||||
pub fn new() -> Self {
|
||||
let choices = MenuChoiceFactory::new();
|
||||
Self {
|
||||
pad: Pad::with_background(BLD_BG).with_clear(),
|
||||
choice_page: Child::new(
|
||||
ChoicePage::new(choices)
|
||||
.with_carousel(true)
|
||||
.with_only_one_item(true),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Menu {
|
||||
type Msg = Never;
|
||||
type Msg = MenuMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg
|
||||
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
self.title
|
||||
.place(Rect::new(Point::new(10, 0), Point::new(128, 8)));
|
||||
self.pad.place(bounds);
|
||||
self.choice_page.place(bounds);
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
self.choice_page.event(ctx, event)
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
self.pad.paint();
|
||||
self.choice_page.paint();
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.choice_page.bounds(sink)
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,21 @@
|
||||
use crate::ui::{
|
||||
component::text::TextStyle,
|
||||
display::{Color, Font},
|
||||
geometry::Offset,
|
||||
display::{toif::Icon, Color, Font},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
component::ButtonStyleSheet,
|
||||
theme::{BG, BLACK, FG, WHITE},
|
||||
};
|
||||
pub use super::super::theme::{BLACK, WHITE};
|
||||
|
||||
pub const BLD_BG: Color = BLACK;
|
||||
pub const BLD_FG: Color = WHITE;
|
||||
|
||||
pub fn bld_button_default() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet::new(BG, FG, false, false, None, Offset::zero())
|
||||
}
|
||||
|
||||
pub fn bld_button_cancel() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet::new(FG, BG, false, false, None, Offset::zero())
|
||||
}
|
||||
include_icon!(LOGO_EMPTY, "model_tr/res/logo_22_33_empty.toif");
|
||||
include_icon!(ICON_TRASH, "model_tr/res/trash.toif");
|
||||
include_icon!(ICON_ALERT, "model_tr/res/alert.toif");
|
||||
include_icon!(ICON_SPINNER, "model_tr/res/spinner.toif");
|
||||
include_icon!(ICON_REDO, "model_tr/res/redo.toif");
|
||||
include_icon!(ICON_EXIT, "model_tr/res/exit.toif");
|
||||
include_icon!(ICON_INFO, "model_tr/res/info.toif");
|
||||
include_icon!(ICON_INFO_INVERTED, "model_tr/res/info_inverted.toif");
|
||||
|
||||
pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::BOLD, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
|
@ -1,54 +0,0 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display::{self, Font},
|
||||
geometry::{Point, Rect},
|
||||
};
|
||||
|
||||
use super::theme::{BLD_BG, BLD_FG};
|
||||
|
||||
pub struct Title {
|
||||
version: &'static str,
|
||||
area: Rect,
|
||||
}
|
||||
|
||||
impl Title {
|
||||
pub fn new(version: &'static str) -> Self {
|
||||
Self {
|
||||
version,
|
||||
area: Rect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Title {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
display::text_top_left(
|
||||
self.area.top_left(),
|
||||
"BOOTLOADER",
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
display::text_top_left(
|
||||
Point::new(self.area.top_left().x + 65, self.area.top_left().y),
|
||||
self.version,
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
display::{self, Font},
|
||||
geometry::{Offset, Rect},
|
||||
};
|
||||
|
||||
use super::theme::{BLD_BG, BLD_FG};
|
||||
|
||||
pub struct Welcome {
|
||||
bg: Pad,
|
||||
}
|
||||
|
||||
impl Welcome {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
bg: Pad::with_background(BLD_BG).with_clear(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Welcome {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(bounds);
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
|
||||
let top_center = self.bg.area.top_center();
|
||||
|
||||
display::text_center(
|
||||
top_center + Offset::y(24),
|
||||
"Get started with",
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
display::text_center(
|
||||
top_center + Offset::y(32),
|
||||
"your Trezor at",
|
||||
Font::NORMAL,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
display::text_center(
|
||||
top_center + Offset::y(48),
|
||||
"trezor.io/start",
|
||||
Font::BOLD,
|
||||
BLD_FG,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
pub enum CancelConfirmMsg {
|
||||
Cancelled,
|
||||
Confirmed,
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
use crate::ui::{
|
||||
component::{Child, Component, Event, EventCtx, Label, Never, Pad},
|
||||
constant::screen,
|
||||
display,
|
||||
geometry::{Alignment::Center, Offset, Point, Rect, TOP_LEFT, TOP_RIGHT},
|
||||
};
|
||||
|
||||
use super::super::{
|
||||
theme,
|
||||
theme::{BG, FG, TITLE_AREA_HEIGHT},
|
||||
};
|
||||
|
||||
const FOOTER_AREA_HEIGHT: i16 = 20;
|
||||
const MESSAGE_AREA_HEIGHT: i16 = 32;
|
||||
const DIVIDER_POSITION: i16 = 43;
|
||||
|
||||
pub struct ErrorScreen<T> {
|
||||
bg: Pad,
|
||||
show_icons: bool,
|
||||
title: Child<Label<T>>,
|
||||
message: Child<Label<T>>,
|
||||
footer: Child<Label<T>>,
|
||||
area: Rect,
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> ErrorScreen<T> {
|
||||
pub fn new(title: T, message: T, footer: T) -> Self {
|
||||
let title = Label::new(title, Center, theme::TEXT_BOLD);
|
||||
let message = Label::new(message, Center, theme::TEXT_NORMAL).vertically_aligned(Center);
|
||||
let footer = Label::new(footer, Center, theme::TEXT_NORMAL).vertically_aligned(Center);
|
||||
|
||||
Self {
|
||||
bg: Pad::with_background(BG).with_clear(),
|
||||
show_icons: true,
|
||||
title: Child::new(title),
|
||||
message: Child::new(message),
|
||||
footer: Child::new(footer),
|
||||
area: Rect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> Component for ErrorScreen<T> {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(screen());
|
||||
|
||||
let title_area = Rect::new(screen().top_left(), screen().top_right() + Offset::y(11));
|
||||
self.title.place(title_area);
|
||||
|
||||
let text_width = self.title.inner().max_size().x;
|
||||
|
||||
if text_width > title_area.width() - 2 * TITLE_AREA_HEIGHT {
|
||||
self.show_icons = false;
|
||||
}
|
||||
|
||||
let message_area = Rect::new(
|
||||
title_area.bottom_left(),
|
||||
title_area.bottom_right() + Offset::y(MESSAGE_AREA_HEIGHT),
|
||||
);
|
||||
self.message.place(message_area);
|
||||
|
||||
let footer_area = Rect::new(
|
||||
screen().bottom_left() + Offset::y(-FOOTER_AREA_HEIGHT),
|
||||
screen().bottom_right(),
|
||||
);
|
||||
self.footer.place(footer_area);
|
||||
|
||||
self.area = bounds;
|
||||
screen()
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
|
||||
if self.show_icons {
|
||||
theme::ICON_WARN_TITLE.draw(screen().top_left(), TOP_LEFT, FG, BG);
|
||||
theme::ICON_WARN_TITLE.draw(screen().top_right(), TOP_RIGHT, FG, BG);
|
||||
}
|
||||
self.title.paint();
|
||||
self.message.paint();
|
||||
// divider line
|
||||
let bar = Rect::from_center_and_size(
|
||||
Point::new(self.area.center().x, DIVIDER_POSITION),
|
||||
Offset::new(self.area.width(), 1),
|
||||
);
|
||||
display::rect_fill(bar, FG);
|
||||
|
||||
self.footer.paint();
|
||||
}
|
||||
}
|
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.
Loading…
Reference in new issue