1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-12 22:26:08 +00:00

feat(eckhart): implement bootloader loader

This commit is contained in:
obrusvit 2025-03-10 18:04:11 +01:00
parent b6f27f3087
commit 942e3953e2
3 changed files with 86 additions and 30 deletions

View File

@ -1,40 +1,96 @@
use crate::ui::{display::Color, geometry::Point, shape, shape::Renderer}; use crate::ui::{
constant::SCREEN,
geometry::{Offset, Rect},
lerp::Lerp,
shape::{self, Renderer},
};
use super::super::constant; use super::{super::theme::BG, ScreenBorder};
pub enum LoaderRange {
Full,
FromTo(f32, f32),
}
pub fn render_loader<'s>( pub fn render_loader<'s>(
center: Point, progress: u16,
inactive_color: Color, border: &'static ScreenBorder,
active_color: Color,
background_color: Color,
range: LoaderRange,
target: &mut impl Renderer<'s>, target: &mut impl Renderer<'s>,
) { ) {
shape::Circle::new(center, constant::LOADER_OUTER) // convert to ration from 0.0 to 1.0
.with_bg(inactive_color) let progress_ratio = (progress as f32 / 1000.0).clamp(0.0, 1.0);
.render(target); let (clip, top_gap) = get_clips(progress_ratio);
render_clipped_border(border, clip, top_gap, u8::MAX, target);
}
match range { fn get_clips(progress_ratio: f32) -> (Rect, Rect) {
LoaderRange::Full => { /// Ratio of total_duration for the bottom part of the border
shape::Circle::new(center, constant::LOADER_OUTER) const BOTTOM_DURATION_RATIO: f32 = 0.125;
.with_bg(active_color) /// Ratio of total_duration for the side parts of the border
.render(target); const SIDES_DURATION_RATIO: f32 = 0.5;
/// Ratio of total_duration for the top part of the border
const TOP_DURATION_RATIO: f32 = 0.375;
const TOP_GAP_ZERO: Rect = Rect::from_center_and_size(
SCREEN.top_center().ofs(Offset::y(ScreenBorder::WIDTH / 2)),
Offset::zero(),
);
const TOP_GAP_FULL: Rect = Rect::from_center_and_size(
SCREEN.top_center().ofs(Offset::y(ScreenBorder::WIDTH / 2)),
Offset::new(SCREEN.width(), ScreenBorder::WIDTH),
);
match progress_ratio {
// Bottom phase growing linearly
p if p < BOTTOM_DURATION_RATIO => {
let bottom_progress = (p / BOTTOM_DURATION_RATIO).clamp(0.0, 1.0);
let width = i16::lerp(0, SCREEN.width(), bottom_progress);
let clip = Rect::from_center_and_size(
SCREEN
.bottom_center()
.ofs(Offset::y(-ScreenBorder::WIDTH / 2)),
Offset::new(width, ScreenBorder::WIDTH),
);
(clip, TOP_GAP_FULL)
} }
LoaderRange::FromTo(start, end) => {
shape::Circle::new(center, constant::LOADER_OUTER) // Sides phase growing up linearly
.with_bg(active_color) p if p < (BOTTOM_DURATION_RATIO + SIDES_DURATION_RATIO) => {
.with_start_angle(start) let sides_progress =
.with_end_angle(end) ((p - BOTTOM_DURATION_RATIO) / SIDES_DURATION_RATIO).clamp(0.0, 1.0);
.render(target); let height = i16::lerp(ScreenBorder::WIDTH, SCREEN.height(), sides_progress);
let clip = Rect::from_bottom_left_and_size(
SCREEN.bottom_left(),
Offset::new(SCREEN.width(), height),
);
(clip, TOP_GAP_FULL)
} }
// Top gap shrinking linearly
p if p < 1.0 => {
let top_progress = ((p - BOTTOM_DURATION_RATIO - SIDES_DURATION_RATIO)
/ TOP_DURATION_RATIO)
.clamp(0.0, 1.0);
let width = i16::lerp(SCREEN.width(), 0, top_progress);
let top_gap = Rect::from_center_and_size(
SCREEN.top_center().ofs(Offset::y(ScreenBorder::WIDTH / 2)),
Offset::new(width, ScreenBorder::WIDTH),
);
(SCREEN, top_gap)
}
// Animation complete
_ => (SCREEN, TOP_GAP_ZERO),
} }
}
shape::Circle::new(center, constant::LOADER_INNER + 2) fn render_clipped_border<'s>(
.with_bg(background_color) border: &'static ScreenBorder,
clip: Rect,
top_gap: Rect,
alpha: u8,
target: &mut impl Renderer<'s>,
) {
target.in_clip(clip, &|target| {
border.render(alpha, target);
});
shape::Bar::new(top_gap)
.with_bg(BG)
.with_fg(BG)
.render(target); .render(target);
} }

View File

@ -1,5 +1,5 @@
mod loader; mod loader;
mod screen_border; mod screen_border;
pub use loader::{render_loader, LoaderRange}; pub use loader::render_loader;
pub use screen_border::ScreenBorder; pub use screen_border::ScreenBorder;

View File

@ -17,7 +17,7 @@ pub struct ScreenBorder {
impl ScreenBorder { impl ScreenBorder {
pub const WIDTH: i16 = 4; pub const WIDTH: i16 = 4;
pub fn new(color: Color) -> Self { pub const fn new(color: Color) -> Self {
let screen = constant::screen(); let screen = constant::screen();
// Top bar: from the right edge of top-left icon to the left edge of top-right // Top bar: from the right edge of top-left icon to the left edge of top-right