1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-18 05:28:40 +00:00

feat(core/rust): model R bootloader implementation in rust

This commit is contained in:
tychovrahe 2022-10-19 23:03:59 +02:00
parent e546346333
commit 7626a99a0f
13 changed files with 993 additions and 1 deletions

View File

@ -0,0 +1,116 @@
use crate::ui::{
component::{text::paragraphs::Paragraphs, Child, Component, Event, EventCtx, Pad},
constant::screen,
display,
display::Color,
geometry::{Point, Rect},
model_tr::{
component::{Button, ButtonMsg::Clicked},
constant::{HEIGHT, WIDTH},
theme::WHITE,
},
};
use super::ReturnToC;
#[derive(Copy, Clone)]
pub enum ConfirmMsg {
Cancel = 1,
Confirm = 2,
}
impl ReturnToC for ConfirmMsg {
fn return_to_c(self) -> u32 {
self as u32
}
}
pub struct Confirm {
bg: Pad,
bg_color: Color,
icon: Option<&'static [u8]>,
message: Child<Paragraphs<&'static str>>,
left: Child<Button<&'static str>>,
right: Child<Button<&'static str>>,
confirm_left: bool,
}
impl Confirm {
pub fn new(
bg_color: Color,
icon: Option<&'static [u8]>,
message: Paragraphs<&'static str>,
left: Button<&'static str>,
right: Button<&'static str>,
confirm_left: bool,
) -> Self {
let mut instance = Self {
bg: Pad::with_background(bg_color),
bg_color,
icon,
message: Child::new(message),
left: Child::new(left),
right: Child::new(right),
confirm_left,
};
instance.bg.clear();
instance
}
}
impl Component for Confirm {
type Msg = ConfirmMsg;
fn place(&mut self, bounds: Rect) -> Rect {
self.bg
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
self.message
.place(Rect::new(Point::new(10, 0), Point::new(118, 50)));
let button_area = bounds.split_bottom(12).1;
self.left.place(button_area);
self.right.place(button_area);
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
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();
if let Some(icon) = self.icon {
display::icon(
Point::new(screen().center().x, 45),
icon,
WHITE,
self.bg_color,
);
}
self.message.paint();
self.left.paint();
self.right.paint();
}
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
self.left.bounds(sink);
self.right.bounds(sink);
}
}

View File

@ -0,0 +1,110 @@
use crate::ui::{
component::{text::paragraphs::Paragraphs, Child, Component, Event, EventCtx, Pad},
geometry::{LinearPlacement, Point, Rect},
model_tr::{
bootloader::{
theme::{BLD_BG, TEXT_NORMAL},
title::Title,
ReturnToC,
},
component::ButtonMsg::Clicked,
},
};
use crate::ui::model_tr::{
bootloader::theme::bld_button_default,
component::{Button, ButtonPos},
constant::{HEIGHT, WIDTH},
};
#[repr(u32)]
#[derive(Copy, Clone)]
pub enum IntroMsg {
Menu = 1,
Host = 2,
}
impl ReturnToC for IntroMsg {
fn return_to_c(self) -> u32 {
self as u32
}
}
pub struct Intro {
bg: Pad,
title: Child<Title>,
host: Child<Button<&'static str>>,
menu: Child<Button<&'static str>>,
text: Child<Paragraphs<&'static str>>,
}
impl Intro {
pub fn new(bld_version: &'static str, vendor: &'static str, version: &'static str) -> Self {
let p1 = Paragraphs::new()
.add(TEXT_NORMAL, version)
.add(TEXT_NORMAL, vendor)
.with_placement(LinearPlacement::vertical().align_at_start());
let mut instance = Self {
bg: Pad::with_background(BLD_BG),
title: Child::new(Title::new(bld_version)),
host: Child::new(Button::with_text(
ButtonPos::Left,
"INSTALL FIRMWARE",
bld_button_default(),
)),
menu: Child::new(Button::with_text(
ButtonPos::Right,
"MENU",
bld_button_default(),
)),
text: Child::new(p1),
};
instance.bg.clear();
instance
}
}
impl Component for Intro {
type Msg = IntroMsg;
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)));
let button_area = bounds.split_bottom(12).1;
self.host.place(button_area);
self.menu.place(button_area);
self.text
.place(Rect::new(Point::new(10, 20), Point::new(118, 50)));
bounds
}
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
if let Some(Clicked) = self.menu.event(ctx, event) {
return Some(Self::Msg::Menu);
};
if let Some(Clicked) = self.host.event(ctx, event) {
return Some(Self::Msg::Host);
};
None
}
fn paint(&mut self) {
self.bg.paint();
self.title.paint();
self.text.paint();
self.host.paint();
self.menu.paint();
}
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
self.title.bounds(sink);
self.text.bounds(sink);
self.host.bounds(sink);
self.menu.bounds(sink);
}
}

View File

@ -0,0 +1,104 @@
use crate::ui::{
component::{Child, Component, Event, EventCtx, Pad},
geometry::{Point, Rect},
model_tr::{
bootloader::{theme::BLD_BG, title::Title, ReturnToC},
constant::{HEIGHT, WIDTH},
},
};
#[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
}
}
pub struct Menu {
bg: Pad,
title: Child<Title>,
// close: Child<Button<&'static str>>,
// reboot: Child<Button<&'static str>>,
// reset: Child<Button<&'static str>>,
}
impl Menu {
pub fn new(bld_version: &'static str) -> Self {
// let content_reboot = IconText::new("REBOOT", REBOOT);
// let content_reset = IconText::new("FACTORY RESET", ERASE);
let mut instance = Self {
bg: Pad::with_background(BLD_BG),
title: Child::new(Title::new(bld_version)),
// close: Child::new(
// Button::with_icon(CLOSE)
// .styled(button_bld_menu())
// .with_expanded_touch_area(Insets::uniform(13)),
// ),
// reboot: Child::new(
// Button::with_icon_and_text(content_reboot).styled(button_bld_menu_item()),
// ),
// reset: Child::new(
// Button::with_icon_and_text(content_reset).styled(button_bld_menu_item()),
// ),
};
instance.bg.clear();
instance
}
}
impl Component for Menu {
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.close.place(Rect::new(
// Point::new(187, 15),
// Point::new(187 + 38, 15 + 38),
// ));
// self.reboot
// .place(Rect::new(Point::new(16, 66), Point::new(16 + 209, 66 + 48)));
// self.reset.place(Rect::new(
// Point::new(16, 122),
// Point::new(16 + 209, 122 + 48),
// ));
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 bounds(&self, _sink: &mut dyn FnMut(Rect)) {
// self.close.bounds(sink);
// self.reboot.bounds(sink);
// self.reset.bounds(sink);
}
}

View File

@ -0,0 +1,393 @@
use crate::{
trezorhal::io::io_button_read,
ui::{
component::{Component, Never},
display::{self, Font},
geometry::Point,
model_tr::constant,
},
};
mod confirm;
mod intro;
mod menu;
mod theme;
mod title;
use crate::ui::{
component::{text::paragraphs::Paragraphs, Event, EventCtx},
constant::{screen, BACKLIGHT_NORMAL, WIDTH},
display::{fade_backlight_duration, Color, TextOverlay},
event::ButtonEvent,
geometry::{LinearPlacement, Offset, Rect},
model_tr::{
bootloader::{
confirm::Confirm,
intro::Intro,
menu::Menu,
theme::{bld_button_cancel, bld_button_default, BLD_BG, BLD_FG},
},
component::{Button, ButtonPos, ResultScreen},
theme::LOGO_EMPTY,
},
util::{from_c_array, from_c_str},
};
const SCREEN_ADJ: Rect = screen().split_top(64).0;
pub trait ReturnToC {
fn return_to_c(self) -> u32;
}
impl ReturnToC for Never {
fn return_to_c(self) -> u32 {
unreachable!()
}
}
impl ReturnToC for () {
fn return_to_c(self) -> u32 {
0
}
}
fn button_eval() -> Option<ButtonEvent> {
let event = io_button_read();
if event == 0 {
return None;
}
let event_type = event >> 24;
let event_btn = event & 0xFFFFFF;
let event = ButtonEvent::new(event_type, event_btn);
if let Ok(event) = event {
return Some(event);
}
None
}
fn run<F>(frame: &mut F) -> u32
where
F: Component,
F::Msg: ReturnToC,
{
frame.place(SCREEN_ADJ);
frame.paint();
fade_backlight_duration(BACKLIGHT_NORMAL as _, 500);
while button_eval().is_some() {}
loop {
let event = button_eval();
if let Some(e) = event {
let mut ctx = EventCtx::new();
let msg = frame.event(&mut ctx, Event::Button(e));
if let Some(message) = msg {
return message.return_to_c();
}
frame.paint();
}
}
}
#[no_mangle]
extern "C" fn screen_install_confirm(
vendor_str: *const cty::c_char,
vendor_str_len: u8,
version: *const cty::c_char,
downgrade: bool,
vendor: bool,
) -> u32 {
let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) });
let version = unwrap!(unsafe { from_c_str(version) });
const ICON: Option<&'static [u8]> = None; //Some(RECEIVE);
let msg = if downgrade {
"Downgrade firmware by"
} else if vendor {
"Change vendor to"
} else {
"Update firmware by"
};
let mut message = Paragraphs::new()
.add(theme::TEXT_NORMAL, msg)
.centered()
.add(theme::TEXT_NORMAL, text)
.centered()
.add(theme::TEXT_NORMAL, version)
.centered();
if vendor || downgrade {
message = message
.add(theme::TEXT_BOLD, "Seed will be erased!")
.centered();
}
message = message.with_placement(LinearPlacement::vertical().align_at_center());
let left = Button::with_text(ButtonPos::Left, "CANCEL", bld_button_cancel());
let right = Button::with_text(ButtonPos::Right, "INSTALL", bld_button_default());
let mut frame = Confirm::new(BLD_BG, ICON, message, left, right, false);
run(&mut frame)
}
#[no_mangle]
extern "C" fn screen_wipe_confirm() -> u32 {
const ICON: Option<&'static [u8]> = None; //Some(ERASE_BIG);
let message = Paragraphs::new()
.add(theme::TEXT_NORMAL, "Do you really want to wipe the device?")
.centered()
.add(theme::TEXT_BOLD, "Seed will be erased!")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let left = Button::with_text(ButtonPos::Left, "WIPE", bld_button_default());
let right = Button::with_text(ButtonPos::Right, "CANCEL", bld_button_cancel());
let mut frame = Confirm::new(BLD_BG, ICON, message, left, right, true);
run(&mut frame)
}
#[no_mangle]
extern "C" fn screen_menu(bld_version: *const cty::c_char) -> u32 {
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
run(&mut Menu::new(bld_version))
}
#[no_mangle]
extern "C" fn screen_intro(
bld_version: *const cty::c_char,
vendor_str: *const cty::c_char,
vendor_str_len: u8,
version: *const cty::c_char,
) -> u32 {
let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) });
let version = unwrap!(unsafe { from_c_str(version) });
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
run(&mut Intro::new(bld_version, vendor, version))
}
fn screen_progress(
text: &str,
progress: u16,
initialize: bool,
fg_color: Color,
bg_color: Color,
_icon: Option<(&[u8], Color)>,
) -> u32 {
if initialize {
display::rect_fill(constant::screen(), bg_color);
}
let loader_area = Rect::new(Point::new(5, 24), Point::new(WIDTH - 5, 24 + 16));
let mut text = TextOverlay::new(text, Font::NORMAL);
text.place(loader_area.center() + Offset::y(Font::NORMAL.text_height() / 2));
let fill_to = (loader_area.width() as u32 * progress as u32) / 1000;
display::bar_with_text_and_fill(loader_area, Some(text), fg_color, bg_color, 0, fill_to as _);
// display::text_center(
// Point::new(constant::WIDTH / 2, 100),
// text,
// Font::NORMAL,
// fg_color,
// bg_color,
// );
// display::loader(progress, -20, fg_color, bg_color, icon);
0
}
const INITIAL_INSTALL_LOADER_COLOR: Color = Color::rgb(0x4A, 0x90, 0xE2);
#[no_mangle]
extern "C" fn screen_install_progress(
progress: u16,
initialize: bool,
_initial_setup: bool,
) -> u32 {
screen_progress(
"INSTALLING FIRMWARE",
progress,
initialize,
BLD_FG,
BLD_BG,
None, //Some((theme::RECEIVE, fg_color)),
)
}
#[no_mangle]
extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) -> u32 {
screen_progress(
"WIPING DEVICE",
progress,
initialize,
theme::BLD_FG,
BLD_BG,
None, //Some((theme::ERASE_BIG, theme::BLD_FG)),
)
}
#[no_mangle]
extern "C" fn screen_connect() -> u32 {
let mut frame = Paragraphs::new()
.add(theme::TEXT_NORMAL, "Waiting for host...")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
frame.place(SCREEN_ADJ);
frame.paint();
0
}
#[no_mangle]
extern "C" fn screen_wipe_success() -> u32 {
let m_top = Paragraphs::new()
.add(theme::TEXT_NORMAL, "Device wiped")
.centered()
.add(theme::TEXT_NORMAL, "successfully.")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let m_bottom = Paragraphs::new()
.add(theme::TEXT_NORMAL, "PLEASE RECONNECT")
.centered()
.add(theme::TEXT_NORMAL, "THE DEVICE")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, m_top, m_bottom, true);
frame.place(SCREEN_ADJ);
frame.paint();
0
}
#[no_mangle]
extern "C" fn screen_wipe_fail() -> u32 {
let m_top = Paragraphs::new()
.add(theme::TEXT_NORMAL, "Device wipe was")
.centered()
.add(theme::TEXT_NORMAL, "not successful.")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let m_bottom = Paragraphs::new()
.add(theme::TEXT_NORMAL, "PLEASE RECONNECT")
.centered()
.add(theme::TEXT_NORMAL, "THE DEVICE")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, m_top, m_bottom, true);
frame.place(SCREEN_ADJ);
frame.paint();
0
}
#[no_mangle]
extern "C" fn screen_boot_empty(_firmware_present: bool) {
display::icon(SCREEN_ADJ.center(), LOGO_EMPTY, BLD_FG, BLD_BG);
}
#[no_mangle]
extern "C" fn screen_install_fail() -> u32 {
let m_top = Paragraphs::new()
.add(theme::TEXT_NORMAL, "Firmware installation was")
.centered()
.add(theme::TEXT_NORMAL, "not successful.")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let m_bottom = Paragraphs::new()
.add(theme::TEXT_NORMAL, "PLEASE RECONNECT")
.centered()
.add(theme::TEXT_NORMAL, "THE DEVICE")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, m_top, m_bottom, true);
frame.place(SCREEN_ADJ);
frame.paint();
0
}
fn screen_install_success_bld(msg: &'static str, complete_draw: bool) -> u32 {
let m_top = Paragraphs::new()
.add(theme::TEXT_NORMAL, "Firmware installed")
.centered()
.add(theme::TEXT_NORMAL, "successfully.")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let m_bottom = Paragraphs::new()
.add(theme::TEXT_NORMAL, msg)
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, m_top, m_bottom, complete_draw);
frame.place(SCREEN_ADJ);
frame.paint();
0
}
fn screen_install_success_initial(msg: &'static str, complete_draw: bool) -> u32 {
let m_top = Paragraphs::new()
.add(theme::TEXT_NORMAL, "Firmware installed")
.centered()
.add(theme::TEXT_NORMAL, "successfully.")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let m_bottom = Paragraphs::new()
.add(theme::TEXT_NORMAL, msg)
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, m_top, m_bottom, complete_draw);
frame.place(SCREEN_ADJ);
frame.paint();
0
}
#[no_mangle]
extern "C" fn screen_install_success(
reboot_msg: *const cty::c_char,
initial_setup: bool,
complete_draw: bool,
) -> u32 {
let msg = unwrap!(unsafe { from_c_str(reboot_msg) });
if initial_setup {
screen_install_success_initial(msg, complete_draw)
} else {
screen_install_success_bld(msg, complete_draw)
}
}
#[no_mangle]
extern "C" fn screen_welcome() -> u32 {
let mut frame = Paragraphs::new()
.add(theme::TEXT_BOLD, "Get started with")
.centered()
.add(theme::TEXT_BOLD, "your trezor at")
.centered()
.add(theme::TEXT_BOLD, "trezor.io/start")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
frame.place(SCREEN_ADJ);
frame.paint();
0
}

View File

@ -0,0 +1,50 @@
use crate::ui::{
component::text::TextStyle,
display::{Color, Font},
model_tr::{
component::{ButtonStyle, ButtonStyleSheet},
theme::{BG, BLACK, FG, WHITE},
},
};
pub const BLD_BG: Color = BLACK;
pub const BLD_FG: Color = WHITE;
// Commonly used corner radius (i.e. for buttons).
pub const RADIUS: u8 = 2;
// Size of icons in the UI (i.e. inside buttons).
pub const ICON_SIZE: i32 = 16;
pub fn bld_button_default() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {
font: Font::NORMAL,
text_color: BG,
border_horiz: true,
},
active: &ButtonStyle {
font: Font::NORMAL,
text_color: FG,
border_horiz: true,
},
}
}
pub fn bld_button_cancel() -> ButtonStyleSheet {
ButtonStyleSheet {
normal: &ButtonStyle {
font: Font::NORMAL,
text_color: FG,
border_horiz: false,
},
active: &ButtonStyle {
font: Font::NORMAL,
text_color: BG,
border_horiz: false,
},
}
}
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);

View File

@ -0,0 +1,52 @@
use crate::ui::{
component::{Component, Event, EventCtx, Never},
display::{self, Font},
geometry::{Point, Rect},
model_tr::bootloader::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,
);
}
fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
}

View File

@ -15,6 +15,7 @@ mod loader;
mod page;
mod passphrase;
mod pin;
mod result;
mod result_anim;
mod result_popup;
mod scrollbar;
@ -43,6 +44,7 @@ pub use loader::{Loader, LoaderMsg, LoaderStyle, LoaderStyleSheet};
pub use page::ButtonPage;
pub use passphrase::{PassphraseEntry, PassphraseEntryMsg};
pub use pin::{PinEntry, PinEntryMsg};
pub use result::ResultScreen;
pub use result_anim::{ResultAnim, ResultAnimMsg};
pub use result_popup::{ResultPopup, ResultPopupMsg};
pub use scrollbar::ScrollBar;

View File

@ -0,0 +1,84 @@
use crate::ui::{
component::{text::paragraphs::Paragraphs, Child, Component, Event, EventCtx, Never, Pad},
constant::{HEIGHT, WIDTH},
display::Color,
geometry::{Point, Rect},
};
pub struct ResultScreen {
bg: Pad,
small_pad: Pad,
fg_color: Color,
bg_color: Color,
message_top: Child<Paragraphs<&'static str>>,
message_bottom: Child<Paragraphs<&'static str>>,
}
impl ResultScreen {
pub fn new(
fg_color: Color,
bg_color: Color,
message_top: Paragraphs<&'static str>,
message_bottom: Paragraphs<&'static str>,
complete_draw: bool,
) -> Self {
let mut instance = Self {
bg: Pad::with_background(bg_color),
small_pad: Pad::with_background(bg_color),
fg_color,
bg_color,
message_top: Child::new(message_top),
message_bottom: Child::new(message_bottom),
};
if complete_draw {
instance.bg.clear();
} else {
instance.small_pad.clear();
}
instance
}
}
impl Component for ResultScreen {
type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect {
self.bg
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
self.message_top
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, 30)));
let bottom_area = Rect::new(Point::new(0, 40), Point::new(WIDTH, HEIGHT));
self.small_pad.place(bottom_area);
self.message_bottom.place(bottom_area);
bounds
}
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
None
}
fn paint(&mut self) {
self.bg.paint();
self.small_pad.paint();
// display::icon(
// Point::new(screen().center().x, 45),
// self.icon,
// self.fg_color,
// self.bg_color,
// );
// display::rect_fill(
// Rect::from_top_left_and_size(Point::new(12, 149), Offset::new(216, 1)),
// self.fg_color,
// );
self.message_top.paint();
self.message_bottom.paint();
}
fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {}
}

View File

@ -9,6 +9,8 @@ pub const LOADER_OUTER: f32 = 20_f32;
pub const LOADER_INNER: f32 = 14_f32;
pub const LOADER_ICON_MAX_SIZE: i16 = 24;
pub const BACKLIGHT_NORMAL: i32 = 150;
pub const fn size() -> Offset {
Offset::new(WIDTH, HEIGHT)
}

View File

@ -1,6 +1,9 @@
#[cfg(feature = "bootloader")]
pub mod bootloader;
pub mod component;
pub mod constant;
pub mod theme;
#[cfg(feature = "micropython")]
pub mod layout;
pub mod screens;

Binary file not shown.

View File

@ -0,0 +1,76 @@
use crate::ui::{
component::{text::paragraphs::Paragraphs, Component},
geometry::LinearPlacement,
model_tr::{
component::ResultScreen,
constant,
theme::{BLACK, TEXT_BOLD, TEXT_NORMAL, WHITE},
},
util::from_c_str,
};
#[no_mangle]
extern "C" fn screen_fatal_error(msg: *const cty::c_char, file: *const cty::c_char) -> u32 {
let m_top = if msg.is_null() {
Paragraphs::new()
.add(TEXT_BOLD, "FATAL ERROR!")
.centered()
// .add(theme::TEXT_WIPE_NORMAL, unwrap!(unsafe { from_c_str(expr) }))
// .centered()
.add(TEXT_NORMAL, unwrap!(unsafe { from_c_str(file) }))
.centered()
.with_placement(LinearPlacement::vertical().align_at_center())
} else {
let msg = unwrap!(unsafe { from_c_str(msg) });
Paragraphs::new()
.add(TEXT_BOLD, "FATAL ERROR!")
.centered()
.add(TEXT_NORMAL, msg)
.centered()
.with_placement(LinearPlacement::vertical().align_at_center())
};
let m_bottom = Paragraphs::new()
.add(TEXT_BOLD, "PLEASE CONTACT")
.centered()
.add(TEXT_BOLD, "TREZOR SUPPORT")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(WHITE, BLACK, m_top, m_bottom, true);
frame.place(constant::screen());
frame.paint();
0
}
#[no_mangle]
extern "C" fn screen_error_shutdown(label: *const cty::c_char, msg: *const cty::c_char) -> u32 {
let label = unwrap!(unsafe { from_c_str(label) });
let m_top = if msg.is_null() {
Paragraphs::new()
.add(TEXT_BOLD, label)
.centered()
.with_placement(LinearPlacement::vertical().align_at_center())
} else {
let msg = unwrap!(unsafe { from_c_str(msg) });
Paragraphs::new()
.add(TEXT_BOLD, label)
.centered()
.add(TEXT_NORMAL, msg)
.centered()
.with_placement(LinearPlacement::vertical().align_at_center())
};
let m_bottom = Paragraphs::new()
.add(TEXT_BOLD, "PLEASE UNPLUG")
.centered()
.add(TEXT_BOLD, "THE DEVICE")
.centered()
.with_placement(LinearPlacement::vertical().align_at_center());
let mut frame = ResultScreen::new(WHITE, BLACK, m_top, m_bottom, true);
frame.place(constant::screen());
frame.paint();
0
}

View File

@ -14,7 +14,7 @@ mod connect;
mod fwinfo;
pub mod intro;
pub mod menu;
mod theme;
pub mod theme;
mod title;
use crate::ui::{