mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-12 06:06:07 +00:00
feat(eckhart): implement bootloader loader
This commit is contained in:
parent
b6f27f3087
commit
942e3953e2
@ -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;
|
||||
|
||||
pub enum LoaderRange {
|
||||
Full,
|
||||
FromTo(f32, f32),
|
||||
}
|
||||
use super::{super::theme::BG, ScreenBorder};
|
||||
|
||||
pub fn render_loader<'s>(
|
||||
center: Point,
|
||||
inactive_color: Color,
|
||||
active_color: Color,
|
||||
background_color: Color,
|
||||
range: LoaderRange,
|
||||
progress: u16,
|
||||
border: &'static ScreenBorder,
|
||||
target: &mut impl Renderer<'s>,
|
||||
) {
|
||||
shape::Circle::new(center, constant::LOADER_OUTER)
|
||||
.with_bg(inactive_color)
|
||||
.render(target);
|
||||
// convert to ration from 0.0 to 1.0
|
||||
let progress_ratio = (progress as f32 / 1000.0).clamp(0.0, 1.0);
|
||||
let (clip, top_gap) = get_clips(progress_ratio);
|
||||
render_clipped_border(border, clip, top_gap, u8::MAX, target);
|
||||
}
|
||||
|
||||
match range {
|
||||
LoaderRange::Full => {
|
||||
shape::Circle::new(center, constant::LOADER_OUTER)
|
||||
.with_bg(active_color)
|
||||
.render(target);
|
||||
fn get_clips(progress_ratio: f32) -> (Rect, Rect) {
|
||||
/// Ratio of total_duration for the bottom part of the border
|
||||
const BOTTOM_DURATION_RATIO: f32 = 0.125;
|
||||
/// Ratio of total_duration for the side parts of the border
|
||||
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)
|
||||
.with_bg(active_color)
|
||||
.with_start_angle(start)
|
||||
.with_end_angle(end)
|
||||
.render(target);
|
||||
|
||||
// Sides phase growing up linearly
|
||||
p if p < (BOTTOM_DURATION_RATIO + SIDES_DURATION_RATIO) => {
|
||||
let sides_progress =
|
||||
((p - BOTTOM_DURATION_RATIO) / SIDES_DURATION_RATIO).clamp(0.0, 1.0);
|
||||
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)
|
||||
.with_bg(background_color)
|
||||
fn render_clipped_border<'s>(
|
||||
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);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
mod loader;
|
||||
mod screen_border;
|
||||
|
||||
pub use loader::{render_loader, LoaderRange};
|
||||
pub use loader::render_loader;
|
||||
pub use screen_border::ScreenBorder;
|
||||
|
@ -17,7 +17,7 @@ pub struct ScreenBorder {
|
||||
|
||||
impl ScreenBorder {
|
||||
pub const WIDTH: i16 = 4;
|
||||
pub fn new(color: Color) -> Self {
|
||||
pub const fn new(color: Color) -> Self {
|
||||
let screen = constant::screen();
|
||||
|
||||
// Top bar: from the right edge of top-left icon to the left edge of top-right
|
||||
|
Loading…
Reference in New Issue
Block a user