From 87ac7446dac346eb6679f425137b99809b49b39a Mon Sep 17 00:00:00 2001 From: BctfN0HUK7Yg Date: Mon, 17 Jan 2022 16:57:09 +0300 Subject: [PATCH] Add new function to animate f32 values (#1039) Co-authored-by: Emil Ernerfeldt --- egui/src/animation_manager.rs | 52 +++++++++++++++++++++++++++++++++++ egui/src/context.rs | 18 ++++++++++++ 2 files changed, 70 insertions(+) diff --git a/egui/src/animation_manager.rs b/egui/src/animation_manager.rs index 8a6795f5..3cc273bf 100644 --- a/egui/src/animation_manager.rs +++ b/egui/src/animation_manager.rs @@ -3,6 +3,7 @@ use crate::{emath::remap_clamp, Id, IdMap, InputState}; #[derive(Clone, Default)] pub(crate) struct AnimationManager { bools: IdMap, + values: IdMap, } #[derive(Clone, Debug)] @@ -12,6 +13,14 @@ struct BoolAnim { toggle_time: f64, } +#[derive(Clone, Debug)] +struct ValueAnim { + from_value: f32, + to_value: f32, + /// when did `value` last toggle? + toggle_time: f64, +} + impl AnimationManager { /// See `Context::animate_bool` for documentation pub fn animate_bool( @@ -56,4 +65,47 @@ impl AnimationManager { } } } + + pub fn animate_value( + &mut self, + input: &InputState, + animation_time: f32, + id: Id, + value: f32, + ) -> f32 { + match self.values.get_mut(&id) { + None => { + self.values.insert( + id, + ValueAnim { + from_value: value, + to_value: value, + toggle_time: -f64::INFINITY, // long time ago + }, + ); + value + } + Some(anim) => { + let time_since_toggle = (input.time - anim.toggle_time) as f32; + // On the frame we toggle we don't want to return the old value, + // so we extrapolate forwards: + let time_since_toggle = time_since_toggle + input.predicted_dt; + let current_value = remap_clamp( + time_since_toggle, + 0.0..=animation_time, + anim.from_value..=anim.to_value, + ); + if anim.to_value != value { + anim.from_value = current_value; //start new animation from current position of playing animation + anim.to_value = value; + anim.toggle_time = input.time; + } + if animation_time == 0.0 { + anim.from_value = value; + anim.to_value = value; + } + current_value + } + } + } } diff --git a/egui/src/context.rs b/egui/src/context.rs index 81e7494d..8b56d26b 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -922,6 +922,24 @@ impl Context { animated_value } + /// Allows you to smoothly change the f32 value. + /// At the first call the value is written to memory. + /// When it is called with a new value, it linearly interpolates to it in the given time. + pub fn animate_value_with_time(&self, id: Id, value: f32, animation_time: f32) -> f32 { + let animated_value = { + let ctx_impl = &mut *self.write(); + ctx_impl + .animation_manager + .animate_value(&ctx_impl.input, animation_time, id, value) + }; + let animation_in_progress = animated_value != value; + if animation_in_progress { + self.request_repaint(); + } + + animated_value + } + /// Clear memory of any animations. pub fn clear_animations(&self) { self.write().animation_manager = Default::default();