1414
1515@dataclass
1616class _DebounceData :
17- t_last : float | None = None
17+ t_last_frame : float = 0
18+ t_last_call : float = 0
1819 timer : threading .Timer | None = None
19- running : bool = False
20+ lock : Lock = None
2021
2122
2223def debounce (arg = None ):
@@ -29,54 +30,37 @@ def debounced(obj, *args, **kwargs):
2930
3031 fname = func .__name__
3132 if obj ._debounce_data .get (fname , None ) is None :
32- obj ._debounce_data [fname ] = _DebounceData (None , None )
33+ obj ._debounce_data [fname ] = _DebounceData (0 , 0 , None , Lock () )
3334
3435 data = obj ._debounce_data [fname ]
36+ t_call = time .time ()
37+ data .t_last_call = t_call
3538
36- # check if we already have a render scheduled
37- if platform .is_pyodide :
38- if data .timer is not None and not data .timer .done ():
39- return
40- else :
41- if data .timer is not None or data .running :
42- return
39+ frame_time = 1.0 / target_fps
4340
4441 def f ():
45- # clear the timer, so we can schedule a new one with the next function call
46- t = time .time ()
47- data .timer = None
48- if platform .is_pyodide :
49- # due to async nature, we need to update t_last before calling func
50- data .t_last = t
42+ with data .lock :
43+ if t_call != data .t_last_call and t_call - data .t_last_frame < frame_time :
44+ return
45+
46+ data .t_last_frame = time .time ()
5147 func (obj , * args , ** kwargs )
52- else :
53- data .t_last = t
54- data .running = True
55- try :
56- func (obj , * args , ** kwargs )
57- finally :
58- data .running = False
59-
60- if data .timer is not None :
61- return
6248
63- if data . t_last is None :
64- # first call -> just call the function immediately
65- data . t_last = time . time ()
49+ t_wait = frame_time - ( t_call - data . t_last_frame )
50+
51+ if t_wait <= 0 :
6652 f ()
6753 return
6854
69- t_wait = max (1 / target_fps - (time .time () - data .t_last ), 0 )
7055 if platform .is_pyodide :
7156 import asyncio
7257 async def _runner ():
7358 if t_wait > 0 :
7459 await asyncio .sleep (t_wait )
7560 f ()
76- data . timer = asyncio .create_task (_runner ())
61+ asyncio .create_task (_runner ())
7762 else :
78- data .timer = threading .Timer (t_wait , f )
79- data .timer .start ()
63+ threading .Timer (t_wait , f ).start ()
8064
8165 debounced ._original = func
8266 return debounced
0 commit comments