mirror of
https://github.com/danbulant/cushy
synced 2026-06-12 19:11:21 +00:00
Debouncing
This commit is contained in:
parent
aeb55e0b94
commit
3f2aace55e
1 changed files with 82 additions and 7 deletions
89
src/value.rs
89
src/value.rs
|
|
@ -9,10 +9,11 @@ use std::sync::atomic::{self, AtomicBool};
|
|||
use std::sync::{Arc, Mutex, MutexGuard, TryLockError};
|
||||
use std::task::{Poll, Waker};
|
||||
use std::thread::ThreadId;
|
||||
use std::time::Duration;
|
||||
|
||||
use ahash::AHashSet;
|
||||
|
||||
use crate::animation::{DynamicTransition, LinearInterpolate};
|
||||
use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearInterpolate, Spawn};
|
||||
use crate::context::sealed::WindowHandle;
|
||||
use crate::context::{self, WidgetContext};
|
||||
use crate::utils::{run_in_bg, IgnorePoison, UnwindsafeCondvar, WithClone};
|
||||
|
|
@ -159,6 +160,33 @@ impl<T> Dynamic<T> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns a new dynamic that contains the updated contents of this dynamic
|
||||
/// at most once every `period`.
|
||||
#[must_use]
|
||||
pub fn debounced_every(&self, period: Duration) -> Self
|
||||
where
|
||||
T: PartialEq + Clone + Send + Sync + 'static,
|
||||
{
|
||||
let debounced = Dynamic::new(self.get());
|
||||
let mut debounce = Debounce::new(debounced.clone(), period);
|
||||
self.for_each_cloned(move |value| debounce.update(value));
|
||||
debounced
|
||||
}
|
||||
|
||||
/// Returns a new dynamic that contains the updated contents of this dynamic
|
||||
/// delayed by `period`. Each time this value is updated, the delay is
|
||||
/// reset.
|
||||
#[must_use]
|
||||
pub fn debounced_with_delay(&self, period: Duration) -> Self
|
||||
where
|
||||
T: PartialEq + Clone + Send + Sync + 'static,
|
||||
{
|
||||
let debounced = Dynamic::new(self.get());
|
||||
let mut debounce = Debounce::new(debounced.clone(), period).extending();
|
||||
self.for_each_cloned(move |value| debounce.update(value));
|
||||
debounced
|
||||
}
|
||||
|
||||
/// Returns a new dynamic that is updated using `U::from(T.clone())` each
|
||||
/// time `self` is updated.
|
||||
#[must_use]
|
||||
|
|
@ -1858,7 +1886,6 @@ impl Validations {
|
|||
self.invalid.map_mut(|invalid| *invalid += 1);
|
||||
|
||||
let invalid_count = self.invalid.clone();
|
||||
let state = self.state.clone();
|
||||
let dynamic = dynamic.clone();
|
||||
let mut initial_generation = dynamic.generation();
|
||||
let mut invalid = true;
|
||||
|
|
@ -1884,11 +1911,6 @@ impl Validations {
|
|||
match current_state {
|
||||
ValidationsState::Resetting => {
|
||||
initial_generation = dynamic.generation();
|
||||
let state = state.clone();
|
||||
|
||||
run_in_bg(move || {
|
||||
state.set(ValidationsState::Initial);
|
||||
});
|
||||
Validation::None
|
||||
}
|
||||
ValidationsState::Initial if initial_generation == dynamic.generation() => {
|
||||
|
|
@ -1963,6 +1985,7 @@ impl Validations {
|
|||
/// Resets the validation status for all related validations.
|
||||
pub fn reset(&self) {
|
||||
self.state.set(ValidationsState::Resetting);
|
||||
self.state.set(ValidationsState::Initial);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2043,3 +2066,55 @@ impl WhenValidation<'_> {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct Debounce<T> {
|
||||
destination: Dynamic<T>,
|
||||
period: Duration,
|
||||
delay: Option<AnimationHandle>,
|
||||
buffer: Dynamic<T>,
|
||||
extend: bool,
|
||||
}
|
||||
|
||||
impl<T> Debounce<T>
|
||||
where
|
||||
T: Clone + PartialEq + Send + Sync + 'static,
|
||||
{
|
||||
pub fn new(destination: Dynamic<T>, period: Duration) -> Self {
|
||||
Self {
|
||||
buffer: Dynamic::new(destination.get()),
|
||||
destination,
|
||||
period,
|
||||
delay: None,
|
||||
extend: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extending(mut self) -> Self {
|
||||
self.extend = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn update(&mut self, value: T) {
|
||||
if self.buffer.replace(value).is_some() {
|
||||
let create_delay = if self.extend {
|
||||
true
|
||||
} else {
|
||||
self.delay
|
||||
.as_ref()
|
||||
.map_or(true, AnimationHandle::is_complete)
|
||||
};
|
||||
|
||||
if create_delay {
|
||||
let destination = self.destination.clone();
|
||||
let buffer = self.buffer.clone();
|
||||
self.delay = Some(
|
||||
self.period
|
||||
.on_complete(move || {
|
||||
destination.set(buffer.get());
|
||||
})
|
||||
.spawn(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue