1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-24 21:32:03 +00:00

chore(eckhart): improve HTC animation

This commit is contained in:
Lukas Bielesch 2025-02-18 13:11:52 +01:00 committed by Vít Obrusník
parent e1cfb7a20b
commit edea4c1fbf
2 changed files with 70 additions and 16 deletions

View File

@ -5,12 +5,14 @@ use crate::{
component::{Component, Event, EventCtx, Never}, component::{Component, Event, EventCtx, Never},
display::Color, display::Color,
geometry::{Offset, Rect}, geometry::{Offset, Rect},
layout_eckhart::{cshape::ScreenBorder, fonts},
shape::{self, Renderer}, shape::{self, Renderer},
}, },
}; };
use super::{constant, theme, Header}; use super::{
super::{component::Header, cshape::ScreenBorder, fonts, theme},
constant::SCREEN,
};
/// A component that displays a border that grows from the bottom of the screen /// A component that displays a border that grows from the bottom of the screen
/// to the top. The animation is parametrizable by color and duration. /// to the top. The animation is parametrizable by color and duration.
@ -67,17 +69,57 @@ impl HoldToConfirmAnim {
self.timer.is_running_within(self.duration) self.timer.is_running_within(self.duration)
} }
fn get_clip(&self) -> Rect { fn get_clips(&self) -> (Rect, Option<Rect>) {
// TODO:
// 1) there will be some easer function
// 2) the growth of the top bar cannot be done with just one clip
let screen = constant::screen();
let ratio = self.timer.elapsed() / self.duration; let ratio = self.timer.elapsed() / self.duration;
let clip_height = ((ratio * screen.height() as f32) as i16).clamp(0, screen.height());
Rect::from_bottom_left_and_size( let bottom_width = self.border.bottom_width();
screen.bottom_left(), let total_height = SCREEN.height();
Offset::new(screen.width(), clip_height), let total_width = SCREEN.width();
)
let circumference = 2 * total_height + total_width + bottom_width;
let bottom_ratio = bottom_width as f32 / circumference as f32;
let vertical_ratio = (2 * total_height) as f32 / circumference as f32;
let upper_ratio = total_width as f32 / circumference as f32;
let vertical_cut = bottom_ratio + vertical_ratio;
if ratio < bottom_ratio {
// Animate the bottom border growing horizontally.
let clip_width = ((ratio / bottom_ratio) * bottom_width as f32) as i16;
let clip_width = clip_width.clamp(0, bottom_width);
(
Rect::from_center_and_size(
SCREEN
.bottom_center()
.ofs(Offset::y(-ScreenBorder::WIDTH / 2)),
Offset::new(clip_width, ScreenBorder::WIDTH),
),
None,
)
} else if ratio < vertical_cut {
// Animate the vertical border growing from the bottom up.
let progress = (ratio - bottom_ratio) / vertical_ratio;
let clip_height = (progress * total_height as f32) as i16;
let clip_height = clip_height.clamp(0, total_height - ScreenBorder::WIDTH);
(
Rect::from_bottom_left_and_size(
SCREEN.bottom_left(),
Offset::new(total_width, clip_height),
),
None,
)
} else {
// Animate the top border growing horizontally towards center.
let progress = (ratio - vertical_cut) / upper_ratio;
let clip_width = total_width - ((progress * total_width as f32) as i16);
(
SCREEN,
Some(Rect::from_center_and_size(
SCREEN.top_center().ofs(Offset::y(ScreenBorder::WIDTH / 2)),
Offset::new(clip_width, ScreenBorder::WIDTH),
)),
)
}
} }
} }
@ -104,8 +146,8 @@ impl Component for HoldToConfirmAnim {
if let Some(text) = self.header_overlay { if let Some(text) = self.header_overlay {
let font = fonts::FONT_SATOSHI_REGULAR_22; let font = fonts::FONT_SATOSHI_REGULAR_22;
let header_pad = Rect::from_top_left_and_size( let header_pad = Rect::from_top_left_and_size(
constant::screen().top_left(), SCREEN.top_left(),
Offset::new(constant::screen().width(), Header::HEADER_HEIGHT), Offset::new(SCREEN.width(), Header::HEADER_HEIGHT),
); );
shape::Bar::new(header_pad) shape::Bar::new(header_pad)
.with_bg(theme::BG) .with_bg(theme::BG)
@ -119,10 +161,17 @@ impl Component for HoldToConfirmAnim {
}); });
} }
// growing border // growing border
let clip = self.get_clip(); let (in_clip, out_clip_opt) = self.get_clips();
target.in_clip(clip, &|target| { target.in_clip(in_clip, &|target| {
self.border.render(target); self.border.render(target);
}); });
// optional out clip for upper line rendering
if let Some(out_clip) = out_clip_opt {
shape::Bar::new(out_clip)
.with_bg(theme::BG)
.with_fg(theme::BG)
.render(target);
}
} }
} }
} }

View File

@ -16,6 +16,7 @@ pub struct ScreenBorder {
} }
impl ScreenBorder { impl ScreenBorder {
pub const WIDTH: i16 = 2;
pub fn new(color: Color) -> Self { pub fn new(color: Color) -> Self {
let screen = constant::screen(); let screen = constant::screen();
@ -59,6 +60,10 @@ impl ScreenBorder {
} }
} }
pub fn bottom_width(&self) -> i16 {
self.side_bars[0].width()
}
pub fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { pub fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
let screen = constant::screen(); let screen = constant::screen();