Skip to content

Commit b2650d4

Browse files
committed
add state variable and timing for selected/released options to reduce accidental touches
1 parent 0f129b8 commit b2650d4

File tree

1 file changed

+56
-22
lines changed

1 file changed

+56
-22
lines changed

adafruit_displayio_layout/widgets/flip_input.py

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ class FlipInput(Widget, Control):
7373
direction, set `False` for arrows in the vertical direction (default = `True`)
7474
:param float animation_time: duration for the animation during flipping between
7575
values, in seconds (default is 0.4 seconds), set to 0.0 or `None` for no animation.
76+
:param float cool_down: minimum duration between activations of the widget with a
77+
continuous pressing, this can be used to reduce the chance of accidental multiple
78+
activations, in seconds (default is 0.0 seconds, no delay). Set to -1.0 to require
79+
the button be released and pressed again for activation (Note: This requires calling
80+
the ``released`` function prior to the next call to ``selected``.)
7681
7782
"""
7883

@@ -94,6 +99,7 @@ def __init__(
9499
alt_touch_padding=0, # touch padding on the non-arrow sides of the Widget
95100
horizontal=True,
96101
animation_time=None,
102+
cool_down=0.0,
97103
**kwargs,
98104
):
99105

@@ -124,6 +130,9 @@ def __init__(
124130
self._display = display
125131

126132
self._animation_time = animation_time
133+
self._cool_down = cool_down
134+
self._last_pressed = time.monotonic()
135+
self._pressed = False # state variable
127136

128137
# Find the maximum bounding box of the text and determine the
129138
# baseline (x,y) start point (top, left)
@@ -412,6 +421,15 @@ def _update_value(self, new_value, animate=True):
412421
self._display.auto_refresh = True
413422
self._update_position() # call Widget superclass function to reposition
414423

424+
def _ok_to_change(self): # checks state variable and timers to determine
425+
# if an update is allowed
426+
if self._cool_down < 0: # if cool_down is negative, require ``released``
427+
# to be called before next change
428+
return not self._pressed
429+
if (time.monotonic() - self._last_pressed) < self._cool_down:
430+
return False # cool_down time has not transpired
431+
return True
432+
415433
def contains(self, touch_point): # overrides, then calls Control.contains(x,y)
416434
"""Returns True if the touch_point is within the widget's touch_boundary."""
417435

@@ -429,34 +447,50 @@ def contains(self, touch_point): # overrides, then calls Control.contains(x,y)
429447
return super().contains((touch_x, touch_y, 0))
430448

431449
def selected(self, touch_point):
432-
"""Response function when Control is selected. Increases value when upper half is pressed
433-
and decreases value when lower half is pressed."""
450+
"""Response function when the Control is selected. Increases value when upper half
451+
is pressed and decreases value when lower half is pressed."""
434452

435453
# Adjust for local position of the widget using self.x and self.y
436454

437-
t_b = self.touch_boundary
455+
if self._ok_to_change():
456+
t_b = self.touch_boundary
438457

439-
if self._horizontal:
440-
if (
441-
t_b[0] <= (touch_point[0] - self.x) < (t_b[0] + t_b[2] // 2)
442-
): # in left half of touch_boundary
443-
self.value = self.value - 1
458+
if self._horizontal:
459+
if (
460+
t_b[0] <= (touch_point[0] - self.x) < (t_b[0] + t_b[2] // 2)
461+
): # in left half of touch_boundary
462+
self.value = self.value - 1
444463

445-
elif (
446-
(t_b[0] + t_b[2] // 2) <= (touch_point[0] - self.x) <= (t_b[0] + t_b[2])
447-
): # in right half of touch_boundary
448-
self.value = self.value + 1
464+
elif (
465+
(t_b[0] + t_b[2] // 2)
466+
<= (touch_point[0] - self.x)
467+
<= (t_b[0] + t_b[2])
468+
): # in right half of touch_boundary
469+
self.value = self.value + 1
449470

450-
else:
451-
if (
452-
t_b[1] <= (touch_point[1] - self.y) < (t_b[1] + t_b[3] // 2)
453-
): # in upper half of touch_boundary
454-
self.value = self.value + 1
455-
456-
elif (
457-
(t_b[1] + t_b[3] // 2) <= (touch_point[1] - self.y) <= (t_b[1] + t_b[3])
458-
): # in lower half of touch_boundary
459-
self.value = self.value - 1
471+
else:
472+
if (
473+
t_b[1] <= (touch_point[1] - self.y) < (t_b[1] + t_b[3] // 2)
474+
): # in upper half of touch_boundary
475+
self.value = self.value + 1
476+
477+
elif (
478+
(t_b[1] + t_b[3] // 2)
479+
<= (touch_point[1] - self.y)
480+
<= (t_b[1] + t_b[3])
481+
): # in lower half of touch_boundary
482+
self.value = self.value - 1
483+
484+
self._pressed = True # update the state variable
485+
self._last_pressed = (
486+
time.monotonic()
487+
) # value changed, so update cool_down timer
488+
489+
def released(self):
490+
"""Response function when the Control is released. Resets the state variables
491+
for handling situation when ``cool_down`` is < 0 that requires `released()` before
492+
reacting another another `selected()`."""
493+
self._pressed = False
460494

461495
@property
462496
def value(self):

0 commit comments

Comments
 (0)