fix(animation): extend cancelling system to support multiple cancel call

This commit fixes cross-monitor drag move by extending cancelling
system. Now each cancel call have its own idx. And only latest cancel
will continue animation. Others will be dropped.
This commit is contained in:
thearturca
2024-07-23 16:26:58 +03:00
parent dfd6e98e9c
commit f25787393c
2 changed files with 48 additions and 15 deletions

View File

@@ -416,12 +416,15 @@ impl Animation {
pub fn new(hwnd: isize) -> Self {
Self { hwnd }
}
pub fn cancel(&mut self) {
/// Returns true if the animation needs to continue
pub fn cancel(&mut self) -> bool {
if !ANIMATION_MANAGER.lock().in_progress(self.hwnd) {
return;
return true;
}
ANIMATION_MANAGER.lock().cancel(self.hwnd);
// should be more than 0
let cancel_idx = ANIMATION_MANAGER.lock().init_cancel(self.hwnd);
let max_duration = Duration::from_secs(1);
let spent_duration = Instant::now();
@@ -434,6 +437,10 @@ impl Animation {
ANIMATION_DURATION.load(Ordering::SeqCst) / 2,
));
}
let latest_cancel_idx = ANIMATION_MANAGER.lock().end_cancel(self.hwnd);
return latest_cancel_idx == cancel_idx;
}
#[allow(clippy::cast_possible_truncation)]
@@ -460,7 +467,11 @@ impl Animation {
mut render_callback: impl FnMut(f64) -> Result<()>,
) -> Result<()> {
if ANIMATION_MANAGER.lock().in_progress(self.hwnd) {
self.cancel();
let should_animate = self.cancel();
if !should_animate {
return Ok(());
}
}
ANIMATION_MANAGER.lock().start(self.hwnd);
@@ -474,8 +485,7 @@ impl Animation {
// check if animation is cancelled
if ANIMATION_MANAGER.lock().is_cancelled(self.hwnd) {
// cancel animation
// set all flags
ANIMATION_MANAGER.lock().end(self.hwnd);
ANIMATION_MANAGER.lock().cancel(self.hwnd);
return Ok(());
}
@@ -485,8 +495,10 @@ impl Animation {
render_callback(progress).ok();
// sleep until next frame
if frame_start.elapsed() < target_frame_time {
std::thread::sleep(target_frame_time - frame_start.elapsed());
let frame_time_elapsed = frame_start.elapsed();
if frame_time_elapsed < target_frame_time {
std::thread::sleep(target_frame_time - frame_time_elapsed);
}
}

View File

@@ -8,7 +8,7 @@ pub static ANIMATIONS_IN_PROGRESS: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug, Clone, Copy)]
struct AnimationState {
pub in_progress: bool,
pub is_cancelled: bool,
pub cancelled_count: usize,
}
#[derive(Debug)]
@@ -31,7 +31,7 @@ impl AnimationManager {
pub fn is_cancelled(&self, hwnd: isize) -> bool {
if let Some(animation_state) = self.animations.get(&hwnd) {
animation_state.is_cancelled
animation_state.cancelled_count > 0
} else {
false
}
@@ -45,9 +45,29 @@ impl AnimationManager {
}
}
pub fn init_cancel(&mut self, hwnd: isize) -> usize {
if let Some(animation_state) = self.animations.get_mut(&hwnd) {
animation_state.cancelled_count += 1;
animation_state.cancelled_count
} else {
0
}
}
pub fn end_cancel(&mut self, hwnd: isize) -> usize {
if let Some(animation_state) = self.animations.get_mut(&hwnd) {
let cancelled_count = animation_state.cancelled_count;
animation_state.cancelled_count -= 1;
return cancelled_count;
} else {
0
}
}
pub fn cancel(&mut self, hwnd: isize) {
if let Some(animation_state) = self.animations.get_mut(&hwnd) {
animation_state.is_cancelled = true;
animation_state.in_progress = false;
}
}
@@ -55,7 +75,7 @@ impl AnimationManager {
if let Entry::Vacant(e) = self.animations.entry(hwnd) {
e.insert(AnimationState {
in_progress: true,
is_cancelled: false,
cancelled_count: 0,
});
ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release);
@@ -70,10 +90,11 @@ impl AnimationManager {
pub fn end(&mut self, hwnd: isize) {
if let Some(animation_state) = self.animations.get_mut(&hwnd) {
animation_state.in_progress = false;
animation_state.is_cancelled = false;
self.animations.remove(&hwnd);
ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release);
if animation_state.cancelled_count == 0 {
self.animations.remove(&hwnd);
ANIMATIONS_IN_PROGRESS.store(self.animations.len(), Ordering::Release);
}
}
}
}