mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-21 09:12:25 +08:00
UI
This commit is contained in:
@@ -20,6 +20,21 @@ MAX_SPEED = 10000.0 # px/s
|
||||
DEBUG = os.getenv("DEBUG_SCROLL", "0") == "1"
|
||||
|
||||
|
||||
# Weights older (steadier) velocity samples more heavily on release.
|
||||
# Finger-lift samples are noisy; trusting earlier samples gives consistent fling velocity.
|
||||
# Reverse-engineered from iOS UIScrollView (tuned at 120Hz touch) by Flutter team:
|
||||
# https://github.com/flutter/flutter/pull/60501
|
||||
# 3 samples ≈ 25ms at 120Hz (iOS) / ~21ms at 140Hz (comma). Scale if touch rate changes.
|
||||
def weighted_velocity(buffer: deque) -> float:
|
||||
if len(buffer) >= 3:
|
||||
return buffer[-3] * 0.6 + buffer[-2] * 0.35 + buffer[-1] * 0.05
|
||||
elif len(buffer) == 2:
|
||||
return buffer[-2] * 0.7 + buffer[-1] * 0.3
|
||||
elif len(buffer) == 1:
|
||||
return buffer[-1]
|
||||
return 0.0
|
||||
|
||||
|
||||
# from https://ariya.io/2011/10/flick-list-with-its-momentum-scrolling-and-deceleration
|
||||
class ScrollState(Enum):
|
||||
STEADY = 0
|
||||
@@ -73,8 +88,14 @@ class GuiScrollPanel2:
|
||||
|
||||
def _update_state(self, bounds_size: float, content_size: float) -> None:
|
||||
"""Runs per render frame, independent of mouse events. Updates auto-scrolling state and velocity."""
|
||||
if self._state == ScrollState.AUTO_SCROLL:
|
||||
max_offset, min_offset = self._get_offset_bounds(bounds_size, content_size)
|
||||
max_offset, min_offset = self._get_offset_bounds(bounds_size, content_size)
|
||||
|
||||
if self._state == ScrollState.STEADY:
|
||||
# if we find ourselves out of bounds, scroll back in (from external layout dimension changes, etc.)
|
||||
if self.get_offset() > max_offset or self.get_offset() < min_offset:
|
||||
self._state = ScrollState.AUTO_SCROLL
|
||||
|
||||
elif self._state == ScrollState.AUTO_SCROLL:
|
||||
# simple exponential return if out of bounds
|
||||
out_of_bounds = self.get_offset() > max_offset or self.get_offset() < min_offset
|
||||
if out_of_bounds and self._handle_out_of_bounds:
|
||||
@@ -145,7 +166,13 @@ class GuiScrollPanel2:
|
||||
# Touch rejection: when releasing finger after swiping and stopping, panel
|
||||
# reports a few erroneous touch events with high velocity, try to ignore.
|
||||
|
||||
# If velocity decelerates very quickly, assume user doesn't intend to auto scroll
|
||||
# If velocity decelerates very quickly, assume user doesn't intend to auto scroll.
|
||||
# Catches two cases: 1) swipe, stop finger, then lift (stale high velocity in buffer)
|
||||
# 2) dirty finger lift where finger rotates/slides producing spurious velocity spike.
|
||||
# TODO: this heuristic false-positives on fast swipes because 140Hz touch polling
|
||||
# jitter causes velocity to oscillate (not real deceleration). Better approaches:
|
||||
# - Use evdev kernel timestamps to eliminate velocity oscillation at the source
|
||||
# - Replace with a time-since-last-event check (40ms timeout) for swipe-stop-lift
|
||||
high_decel = False
|
||||
if len(self._velocity_buffer) > 2:
|
||||
# We limit max to first half since final few velocities can surpass first few
|
||||
@@ -160,6 +187,8 @@ class GuiScrollPanel2:
|
||||
print('deceleration too high, going to STEADY')
|
||||
high_decel = True
|
||||
|
||||
self._velocity = weighted_velocity(self._velocity_buffer)
|
||||
|
||||
# If final velocity is below some threshold, switch to steady state too
|
||||
low_speed = abs(self._velocity) <= MIN_VELOCITY_FOR_CLICKING * 1.5 # plus some margin
|
||||
|
||||
|
||||
Reference in New Issue
Block a user