feat(core): Add preliminary anim frame support

matejcik/one-of
Jan Pochyla 3 years ago committed by matejcik
parent be3e99b96d
commit 117a0bd518

@ -135,35 +135,42 @@ pub enum Event {
} }
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub struct TimerToken(usize); pub struct TimerToken(u32);
impl TimerToken { impl TimerToken {
/// Value of an invalid (or missing) token. /// Value of an invalid (or missing) token.
pub const INVALID: TimerToken = TimerToken(0); pub const INVALID: TimerToken = TimerToken(0);
pub fn from_raw(raw: usize) -> Self { pub const fn from_raw(raw: u32) -> Self {
Self(raw) Self(raw)
} }
pub fn into_raw(self) -> usize { pub const fn into_raw(self) -> u32 {
self.0 self.0
} }
} }
pub struct EventCtx { pub struct EventCtx {
timers: Vec<(TimerToken, Duration), { Self::MAX_TIMERS }>, timers: Vec<(TimerToken, Duration), { Self::MAX_TIMERS }>,
next_token: usize, next_token: u32,
paint_requested: bool, paint_requested: bool,
} }
impl EventCtx { impl EventCtx {
/// Timer token dedicated for animation frames.
pub const ANIM_FRAME_TIMER: TimerToken = TimerToken(1);
// 0 == `TimerToken::INVALID`,
// 1 == `Self::ANIM_FRAME_TIMER`.
const STARTING_TIMER_TOKEN: u32 = 2;
/// Maximum amount of timers requested in one event tick. /// Maximum amount of timers requested in one event tick.
const MAX_TIMERS: usize = 4; const MAX_TIMERS: usize = 4;
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
timers: Vec::new(), timers: Vec::new(),
next_token: 1, next_token: Self::STARTING_TIMER_TOKEN,
paint_requested: false, paint_requested: false,
} }
} }
@ -182,21 +189,37 @@ impl EventCtx {
/// Request a timer event to be delivered after `deadline` elapses. /// Request a timer event to be delivered after `deadline` elapses.
pub fn request_timer(&mut self, deadline: Duration) -> TimerToken { pub fn request_timer(&mut self, deadline: Duration) -> TimerToken {
let token = self.next_timer_token(); let token = self.next_timer_token();
if self.timers.push((token, deadline)).is_err() { self.register_timer(token, deadline);
// The timer queue is full. Let's just ignore this request.
#[cfg(feature = "ui_debug")]
panic!("timer queue is full");
}
token token
} }
/// Request an animation frame timer to fire as soon as possible.
pub fn request_anim_frame(&mut self) {
self.register_timer(Self::ANIM_FRAME_TIMER, Duration::ZERO);
}
pub fn pop_timer(&mut self) -> Option<(TimerToken, Duration)> { pub fn pop_timer(&mut self) -> Option<(TimerToken, Duration)> {
self.timers.pop() self.timers.pop()
} }
fn register_timer(&mut self, token: TimerToken, deadline: Duration) {
if self.timers.push((token, deadline)).is_err() {
// The timer queue is full, this would be a development error in the layout
// layer. Let's panic in the debug env.
#[cfg(feature = "ui_debug")]
panic!("timer queue is full");
}
}
fn next_timer_token(&mut self) -> TimerToken { fn next_timer_token(&mut self) -> TimerToken {
let token = TimerToken(self.next_token); let token = TimerToken(self.next_token);
self.next_token += 1; // We start again from the beginning if the token counter overflows. This would
// probably happen in case of a bug and a long-running session. Let's risk the
// collisions in such case.
self.next_token = self
.next_token
.checked_add(1)
.unwrap_or(Self::STARTING_TIMER_TOKEN);
token token
} }
} }

@ -254,7 +254,7 @@ impl TryFrom<Obj> for TimerToken {
type Error = Error; type Error = Error;
fn try_from(value: Obj) -> Result<Self, Self::Error> { fn try_from(value: Obj) -> Result<Self, Self::Error> {
let raw: usize = value.try_into()?; let raw: u32 = value.try_into()?;
let this = Self::from_raw(raw); let this = Self::from_raw(raw);
Ok(this) Ok(this)
} }

@ -67,10 +67,14 @@ impl Loader {
pub fn progress(&self, now: Instant) -> Option<u16> { pub fn progress(&self, now: Instant) -> Option<u16> {
match &self.state { match &self.state {
State::Initial => None, State::Initial => None,
State::Growing(animation) | State::Shrinking(animation) => Some(animation.value(now)), State::Growing(anim) | State::Shrinking(anim) => Some(anim.value(now)),
} }
} }
pub fn is_started(&self) -> bool {
matches!(self.state, State::Growing(_) | State::Shrinking(_))
}
pub fn is_finished(&self, now: Instant) -> bool { pub fn is_finished(&self, now: Instant) -> bool {
self.progress(now) == Some(display::LOADER_MAX) self.progress(now) == Some(display::LOADER_MAX)
} }
@ -79,7 +83,13 @@ impl Loader {
impl Component for Loader { impl Component for Loader {
type Msg = Never; type Msg = Never;
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> { fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
if let Event::Timer(EventCtx::ANIM_FRAME_TIMER) = event {
if self.is_started() {
ctx.request_paint();
ctx.request_anim_frame();
}
}
None None
} }

Loading…
Cancel
Save