diff --git a/src/app.rs b/src/app.rs index 3c63491..505ace8 100644 --- a/src/app.rs +++ b/src/app.rs @@ -420,7 +420,7 @@ impl + 'static> App { let main_loop_tracing_span = tracing::debug_span!("main loop"); let mut time_of_last_render = Instant::now(); - let mut time_since_last_render = Duration::ZERO; + let mut time_since_last_render_request = Duration::ZERO; while let Some(event) = self.event_chan.blocking_recv() { let mut events = vec![event]; // batch events @@ -439,7 +439,7 @@ impl + 'static> App { } if let Some(root_pod) = self.root_pod.as_mut() { - let cx_state = &mut CxState::new(&mut self.events, time_since_last_render); + let cx_state = &mut CxState::new(&mut self.events, time_since_last_render_request); let mut cx = EventCx { is_handled: false, @@ -453,12 +453,17 @@ impl + 'static> App { } self.send_events(); - let rerender_requested = self.render(time_since_last_render)?; + let rerender_requested = self.render(time_since_last_render_request)?; + // TODO this is a workaround (I consider this at least as that) for getting animations right + // There's likely a cleaner solution if rerender_requested { self.request_render_notifier.notify_one(); + time_since_last_render_request = time_of_last_render.elapsed(); + } else { + time_since_last_render_request = Duration::ZERO; } - time_since_last_render = time_of_last_render.elapsed(); time_of_last_render = Instant::now(); + if quit { break; } diff --git a/src/view/animatables.rs b/src/view/animatables.rs index 4f944a8..3a5d8b8 100644 --- a/src/view/animatables.rs +++ b/src/view/animatables.rs @@ -9,10 +9,10 @@ use crate::{ // This is basically a View trait without (but this may be subject to change, to allow animations based on the AppState (via e.g. event callbacks)) pub trait Animatable: Send + Sync { - /// Associated state for the view. + /// Associated state for the animatable. type State: Send; - /// Associated state for the view. + /// Associated state for the animatable. type Element: AnimatableElement; /// Build the associated widget and initialize state. @@ -33,7 +33,7 @@ pub trait Animatable: Send + Sync { /// Propagate a message. /// /// Handle a message, propagating to children if needed. Here, `id_path` is a slice - /// of ids beginning at a child of this view. + /// of ids beginning at a child of this animatable. fn message( &self, id_path: &[Id], @@ -58,16 +58,15 @@ impl, R: Animatable> Animatable for Lerp { type Element = widget::animatables::Lerp; fn build(&self, cx: &mut Cx) -> (Id, Self::State, Self::Element) { - let (id, (state, el)) = cx.with_new_id(|cx| { + let (id, (state, element)) = cx.with_new_id(|cx| { let (ratio_id, ratio_state, ratio_element) = self.ratio.build(cx); let (tweenable_id, tweenable_state, tweenable_element) = self.tweenable.build(cx); - let element = widget::animatables::Lerp::new(tweenable_element, ratio_element); ( (tweenable_id, tweenable_state, ratio_id, ratio_state), - element, + widget::animatables::Lerp::new(tweenable_element, ratio_element), ) }); - (id, state, el) + (id, state, element) } fn rebuild( @@ -236,7 +235,7 @@ pub trait Tweenable: Send + Sync { /// Build the associated widget and initialize state. fn build(&self, cx: &mut Cx) -> (Id, Self::State, Self::Element); - /// Update the associated value. + /// Update the associated element. /// /// Returns an indication of what, if anything, has changed. fn rebuild( @@ -245,7 +244,7 @@ pub trait Tweenable: Send + Sync { prev: &Self, id: &mut Id, state: &mut Self::State, - value: &mut Self::Element, + element: &mut Self::Element, ) -> ChangeFlags; /// Propagate a message. diff --git a/src/widget/animatables.rs b/src/widget/animatables.rs index f5b7f29..9b26249 100644 --- a/src/widget/animatables.rs +++ b/src/widget/animatables.rs @@ -45,8 +45,6 @@ macro_rules! impl_animatable_for_primitive { } // All builtin number types -impl_animatable_for_primitive!(f64); -impl_animatable_for_primitive!(f32); impl_animatable_for_primitive!(i8); impl_animatable_for_primitive!(u8); impl_animatable_for_primitive!(i16); @@ -60,6 +58,9 @@ impl_animatable_for_primitive!(u128); impl_animatable_for_primitive!(isize); impl_animatable_for_primitive!(usize); +impl_animatable_for_primitive!(f32); +impl_animatable_for_primitive!(f64); + #[derive(Clone, Debug)] pub struct LowPassIIR { pub(crate) target: AT, @@ -91,7 +92,7 @@ impl> AnimatableElement for LowPassIIR let target_value = self.target.animate(cx); if let Some(value) = &mut self.value { if (*target_value - *value).abs() > 0.0001 { - let delta_time = cx.time_since_last_render().as_secs_f64() * 100.0; // could be a different factor, and maybe more precisely a frequency based cutoff or something like that + let delta_time = cx.time_since_last_render_request().as_secs_f64() * 100.0; // could be a different factor, and maybe more precisely a frequency based cutoff or something like that let time_adjusted_decay = 1.0 - ((1.0 - self.decay.clamp(0.0, 1.0)).powf(delta_time)); *value += time_adjusted_decay * (*target_value - *value); @@ -154,7 +155,7 @@ impl, TW: TweenableElement> Animatable let duration_as_secs = self.duration.as_secs_f64(); let current_time_as_secs = self.current_time.as_secs_f64(); let new_time = (current_time_as_secs - + *play_speed * cx.time_since_last_render().as_secs_f64()) + + *play_speed * cx.time_since_last_render_request().as_secs_f64()) .clamp(0.0, duration_as_secs); // avoid division by zero let ratio = if duration_as_secs == 0.0 { diff --git a/src/widget/core.rs b/src/widget/core.rs index cc5c27a..9f2937c 100644 --- a/src/widget/core.rs +++ b/src/widget/core.rs @@ -20,14 +20,14 @@ message!(Send); /// Static state that is shared between most contexts. pub struct CxState<'a> { messages: &'a mut Vec, - pub(crate) time_since_last_render: Duration, // in seconds TODO Duration instead of f64? + pub(crate) time_since_last_render_request: Duration, // in seconds TODO Duration instead of f64? } impl<'a> CxState<'a> { - pub fn new(messages: &'a mut Vec, time_since_last_render: Duration) -> Self { + pub fn new(messages: &'a mut Vec, time_since_last_render_request: Duration) -> Self { Self { messages, - time_since_last_render, + time_since_last_render_request, } } } @@ -144,8 +144,8 @@ impl_context_method!( self.widget_state.flags |= PodFlags::REQUEST_ANIMATION; } - pub fn time_since_last_render(&self) -> Duration { - self.cx_state.time_since_last_render + pub fn time_since_last_render_request(&self) -> Duration { + self.cx_state.time_since_last_render_request } /// Notify Trui that this widgets view context changed.