Properly reverse bool animation if value changes before it's finished (#3577)

<!--
Please read the "Making a PR" section of
[`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md)
before opening a Pull Request!

* Keep your PR:s small and focused.
* If applicable, add a screenshot or gif.
* If it is a non-trivial addition, consider adding a demo for it to
`egui_demo_lib`, or a new example.
* Do NOT open PR:s from your `master` branch, as that makes it hard for
maintainers to add commits to your PR.
* Remember to run `cargo fmt` and `cargo cranky`.
* Open the PR as a draft until you have self-reviewed it and run
`./scripts/check.sh`.
* When you have addressed a PR comment, mark it as resolved.

Please be patient! I will review your PR, but my time is limited!
-->

Closes <https://github.com/emilk/egui/issues/3576>.
This commit is contained in:
YgorSouza 2023-11-21 10:39:43 +01:00 committed by GitHub
parent 39271c3adf
commit 78a93f81f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 23 additions and 27 deletions

View File

@ -1,4 +1,7 @@
use crate::{emath::remap_clamp, Id, IdMap, InputState}; use crate::{
emath::{remap_clamp, NumExt as _},
Id, IdMap, InputState,
};
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub(crate) struct AnimationManager { pub(crate) struct AnimationManager {
@ -8,10 +11,8 @@ pub(crate) struct AnimationManager {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct BoolAnim { struct BoolAnim {
value: bool, last_value: f32,
last_tick: f64,
/// when did `value` last toggle?
toggle_time: f64,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -33,38 +34,33 @@ impl AnimationManager {
id: Id, id: Id,
value: bool, value: bool,
) -> f32 { ) -> f32 {
let (start, end) = if value { (0.0, 1.0) } else { (1.0, 0.0) };
match self.bools.get_mut(&id) { match self.bools.get_mut(&id) {
None => { None => {
self.bools.insert( self.bools.insert(
id, id,
BoolAnim { BoolAnim {
value, last_value: end,
toggle_time: -f64::INFINITY, // long time ago last_tick: input.time - input.stable_dt as f64,
}, },
); );
if value { end
1.0
} else {
0.0
}
} }
Some(anim) => { Some(anim) => {
if anim.value != value { let BoolAnim {
anim.value = value; last_value,
anim.toggle_time = input.time; last_tick,
} } = anim;
let current_time = input.time;
let time_since_toggle = (input.time - anim.toggle_time) as f32; let elapsed = ((current_time - *last_tick) as f32).at_most(input.stable_dt);
let new_value = *last_value + (end - start) * elapsed / animation_time;
// On the frame we toggle we don't want to return the old value, *last_value = if new_value.is_finite() {
// so we extrapolate forwards: new_value.clamp(0.0, 1.0)
let time_since_toggle = time_since_toggle + input.predicted_dt;
if value {
remap_clamp(time_since_toggle, 0.0..=animation_time, 0.0..=1.0)
} else { } else {
remap_clamp(time_since_toggle, 0.0..=animation_time, 1.0..=0.0) end
} };
*last_tick = current_time;
*last_value
} }
} }
} }