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

perf(core): use 16-bit duration for Button long-press duration

Also, use zero duration to disable long-press mechanism.

[no changelog]
This commit is contained in:
Roman Zeyde 2025-06-08 11:56:39 +03:00
parent 0b4c44e32f
commit a7849ab838
10 changed files with 58 additions and 32 deletions

View File

@ -10,6 +10,19 @@ const MILLIS_PER_MINUTE: u32 = MILLIS_PER_SEC * 60;
const MILLIS_PER_HOUR: u32 = MILLIS_PER_MINUTE * 60;
const MILLIS_PER_DAY: u32 = MILLIS_PER_HOUR * 24;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ShortDuration {
millis: u16,
}
impl ShortDuration {
pub const ZERO: Self = Self::from_millis(0);
pub const fn from_millis(millis: u16) -> Self {
Self { millis }
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
pub struct Duration {
millis: u32,
@ -168,6 +181,12 @@ impl Div<Duration> for Duration {
}
}
impl From<ShortDuration> for Duration {
fn from(value: ShortDuration) -> Self {
Self::from_millis(value.millis.into())
}
}
/* Instants can wrap around and we want them to be comparable even after
* wrapping around. This works by setting a maximum allowable difference
* between two Instants to half the range. In checked_add and checked_sub, we

View File

@ -2,7 +2,7 @@
use crate::trezorhal::haptic::{self, HapticEffect};
use crate::{
strutil::TString,
time::Duration,
time::ShortDuration,
ui::{
component::{
Component, ComponentExt, Event, EventCtx, FixedHeightBar, MsgMap, Split, Timer,
@ -41,7 +41,7 @@ pub struct Button {
content: ButtonContent,
styles: ButtonStyleSheet,
state: State,
long_press: Duration,
long_press: ShortDuration, // long press requires non-zero duration
long_timer: Timer,
haptics: bool,
}
@ -58,7 +58,7 @@ impl Button {
touch_expand: Insets::zero(),
styles: theme::button_default(),
state: State::Initial,
long_press: Duration::ZERO,
long_press: ShortDuration::ZERO,
long_timer: Timer::new(),
haptics: true,
}
@ -94,7 +94,8 @@ impl Button {
self
}
pub fn with_long_press(mut self, duration: Duration) -> Self {
pub fn with_long_press(mut self, duration: ShortDuration) -> Self {
debug_assert_ne!(duration, ShortDuration::ZERO);
self.long_press = duration;
self
}
@ -251,8 +252,8 @@ impl Component for Button {
haptic::play(HapticEffect::ButtonPress);
}
self.set(ctx, State::Pressed);
if self.long_press != Duration::ZERO {
self.long_timer.start(ctx, self.long_press)
if self.long_press != ShortDuration::ZERO {
self.long_timer.start(ctx, self.long_press.into())
}
return Some(ButtonMsg::Pressed);
}

View File

@ -2,7 +2,7 @@ pub mod backlight;
pub mod bootloader;
use crate::{
time::Duration,
time::ShortDuration,
ui::{
component::{
text::{layout::Chunks, LineBreaking, PageBreaking, TextStyle},
@ -19,7 +19,7 @@ use super::{
fonts,
};
pub const ERASE_HOLD_DURATION: Duration = Duration::from_millis(1500);
pub const ERASE_HOLD_DURATION: ShortDuration = ShortDuration::from_millis(1500);
// Color palette.
pub const WHITE: Color = Color::rgb(0xFF, 0xFF, 0xFF);

View File

@ -2,7 +2,7 @@
use crate::trezorhal::haptic::{play, HapticEffect};
use crate::{
strutil::TString,
time::Duration,
time::ShortDuration,
ui::{
component::{Component, Event, EventCtx, Timer},
display::{toif::Icon, Color, Font},
@ -30,7 +30,7 @@ pub struct Button {
text_align: Alignment,
radius: Option<u8>,
state: State,
long_press: Option<Duration>,
long_press: ShortDuration, // long press requires non-zero duration
long_timer: Timer,
haptic: bool,
}
@ -50,7 +50,7 @@ impl Button {
text_align: Alignment::Start,
radius: None,
state: State::Initial,
long_press: None,
long_press: ShortDuration::ZERO,
long_timer: Timer::new(),
haptic: true,
}
@ -87,8 +87,9 @@ impl Button {
self
}
pub fn with_long_press(mut self, duration: Duration) -> Self {
self.long_press = Some(duration);
pub fn with_long_press(mut self, duration: ShortDuration) -> Self {
debug_assert_ne!(duration, ShortDuration::ZERO);
self.long_press = duration;
self
}
@ -271,8 +272,8 @@ impl Component for Button {
play(HapticEffect::ButtonPress);
}
self.set(ctx, State::Pressed);
if let Some(duration) = self.long_press {
self.long_timer.start(ctx, duration);
if self.long_press != ShortDuration::ZERO {
self.long_timer.start(ctx, self.long_press.into());
}
return Some(ButtonMsg::Pressed);
}

View File

@ -1,5 +1,5 @@
use crate::{
time::Duration,
time::{Duration, ShortDuration},
translations::TR,
ui::{
component::{Component, Event, EventCtx},
@ -180,7 +180,7 @@ impl HoldToConfirm {
pub fn new(circle_color: Color, circle_inner_color: Color) -> Self {
let button = Button::new(ButtonContent::Empty)
.styled(theme::button_default())
.with_long_press(Duration::from_millis(2200))
.with_long_press(ShortDuration::from_millis(2200))
.without_haptics();
Self {
title: Label::new(

View File

@ -3,7 +3,7 @@ pub mod bootloader;
pub mod backlight;
use crate::{
time::Duration,
time::ShortDuration,
ui::{
component::{
text::{layout::Chunks, LineBreaking, PageBreaking, TextStyle},
@ -20,7 +20,7 @@ use super::{
fonts,
};
pub const ERASE_HOLD_DURATION: Duration = Duration::from_millis(1500);
pub const ERASE_HOLD_DURATION: ShortDuration = ShortDuration::from_millis(1500);
// Color palette.
pub const WHITE: Color = Color::rgb(0xFF, 0xFF, 0xFF);

View File

@ -2,7 +2,7 @@
use crate::trezorhal::haptic::{play, HapticEffect};
use crate::{
strutil::TString,
time::Duration,
time::{Duration, ShortDuration},
ui::{
component::{text::TextStyle, Component, Event, EventCtx, Timer},
constant,
@ -42,7 +42,7 @@ pub struct Button {
text_align: Alignment,
radius_or_gradient: RadiusOrGradient,
state: State,
long_press: Option<Duration>,
long_press: ShortDuration, // long press requires non-zero duration
long_timer: Timer,
haptic: bool,
}
@ -76,7 +76,7 @@ impl Button {
text_align: Alignment::Center,
radius_or_gradient: RadiusOrGradient::None,
state: State::Initial,
long_press: None,
long_press: ShortDuration::ZERO,
long_timer: Timer::new(),
haptic: true,
}
@ -168,8 +168,9 @@ impl Button {
self
}
pub fn with_long_press(mut self, duration: Duration) -> Self {
self.long_press = Some(duration);
pub fn with_long_press(mut self, duration: ShortDuration) -> Self {
debug_assert_ne!(duration, ShortDuration::ZERO);
self.long_press = duration;
self
}
@ -223,7 +224,11 @@ impl Button {
}
pub fn long_press(&self) -> Option<Duration> {
self.long_press
if self.long_press != ShortDuration::ZERO {
Some(self.long_press.into())
} else {
None
}
}
pub fn is_disabled(&self) -> bool {
@ -584,7 +589,7 @@ impl Component for Button {
play(HapticEffect::ButtonPress);
}
self.set(ctx, State::Pressed);
if let Some(duration) = self.long_press {
if let Some(duration) = self.long_press() {
self.long_timer.start(ctx, duration);
}
return Some(ButtonMsg::Pressed);

View File

@ -57,7 +57,7 @@ impl HoldToConfirmAnim {
pub fn new() -> Self {
let default_color = theme::GREEN_LIME;
Self {
total_duration: theme::CONFIRM_HOLD_DURATION,
total_duration: theme::CONFIRM_HOLD_DURATION.into(),
color: default_color,
border: ScreenBorder::new(default_color),
timer: Stopwatch::default(),

View File

@ -2,7 +2,7 @@ use crate::{
error::Error,
io::BinaryData,
strutil::TString,
time::Duration,
time::ShortDuration,
translations::TR,
ui::{
component::{text::TextStyle, Component, Event, EventCtx, Label, Never},
@ -24,7 +24,7 @@ use super::{
ActionBar, ActionBarMsg, Hint,
};
const LOCK_HOLD_DURATION: Duration = Duration::from_millis(3000);
const LOCK_HOLD_DURATION: ShortDuration = ShortDuration::from_millis(3000);
/// Full-screen component for the homescreen and lockscreen.
pub struct Homescreen {

View File

@ -1,5 +1,5 @@
use crate::{
time::Duration,
time::ShortDuration,
ui::component::text::{
layout::{Chunks, LineBreaking, PageBreaking},
TextStyle,
@ -14,8 +14,8 @@ use super::{
*,
};
pub const CONFIRM_HOLD_DURATION: Duration = Duration::from_millis(1500);
pub const ERASE_HOLD_DURATION: Duration = Duration::from_millis(1500);
pub const CONFIRM_HOLD_DURATION: ShortDuration = ShortDuration::from_millis(1500);
pub const ERASE_HOLD_DURATION: ShortDuration = ShortDuration::from_millis(1500);
// Text styles
/// Alias for use with copied code, might be deleted later