| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- import time
- from threading import Thread
- from ..tracker import GestureTracker
- from ..geometry import Positionable
- from utils import PointGesture
- class TapGesture(PointGesture):
- """
- A tap gesture is triggered when a touch point releases from the screen
- within a certain time and distance from its 'point_down' event.
- """
- _type = 'tap'
- class SingleTapGesture(TapGesture):
- """
- A single tap gesture is triggered after a regular tap gesture, if no double
- tap is triggered for that gesture.
- """
- _type = 'single_tap'
- class DoubleTapGesture(TapGesture):
- """
- A double tap gesture is triggered if two sequential taps are triggered
- within a certain time and distance of eachother.
- """
- _type = 'double_tap'
- class TapTracker(GestureTracker):
- supported_gestures = [TapGesture, SingleTapGesture, DoubleTapGesture]
- configurable = ['tap_distance', 'tap_time', 'double_tap_time',
- 'double_tap_distance', 'update_rate', 'propagate_up_event']
- def __init__(self, window=None):
- super(TapTracker, self).__init__(window)
- # Map of touch object id to tuple (timestamp, position) of point down
- self.reg = {}
- # Maximum radius in which a touch point can move in order to be a tap
- # event in pixels
- self.tap_distance = 20
- # Maximum time between 'down' and 'up' of a tap event in seconds
- self.tap_time = .2
- # Maximum time in seconds and distance in pixels between two taps to
- # count as double tap
- self.double_tap_time = .3
- self.double_tap_distance = 30
- # Times per second to detect single taps
- self.update_rate = 30
- # Whether to stop propagation of the 'point_up' event to parent widgets
- # If False, this reserves tap events to child widgets
- self.propagate_up_event = True
- self.reset_last_tap()
- self.single_tap_thread = Thread(target=self.detect_single_tap)
- self.single_tap_thread.daemon = True
- self.single_tap_thread.start()
- def detect_single_tap(self):
- """
- Iteration function for single-tap detection thread.
- """
- while True:
- time_diff = time.time() - self.last_tap_time
- if self.last_tap and time_diff > self.double_tap_time:
- # Last tap is too long ago to be a double tap, so trigger a
- # single tap
- self.trigger(SingleTapGesture(None, self.last_tap))
- self.reset_last_tap()
- time.sleep(1. / self.update_rate)
- def reset_last_tap(self):
- self.last_tap_time = 0
- self.last_tap = None
- def on_point_down(self, event):
- self.reg[event.point.get_id()] = time.time(), event
- def on_point_move(self, event):
- oid = event.point.get_id()
- if oid not in self.reg:
- return
- # If a stationary point moves beyond a threshold, delete it so that the
- # 'up' event will not trigger a 'tap'
- t, down_event = self.reg[oid]
- if event.distance_to(down_event) > self.tap_distance:
- del self.reg[oid]
- def on_point_up(self, event):
- oid = event.point.get_id()
- # Assert that the point has not been deleted by a 'move' event yet
- if oid not in self.reg:
- return
- down_time = self.reg[oid][0]
- del self.reg[oid]
- # Only trigger a tap event if the 'up' is triggered within a certain
- # time afer the 'down'
- current_time = time.time()
- if current_time - down_time > self.tap_time:
- return
- if not self.propagate_up_event:
- event.stop_propagation()
- tap = TapGesture(event)
- self.trigger(tap)
- # Trigger double tap if the threshold has not not expired yet
- if self.last_tap:
- if self.last_tap.distance_to(tap) <= self.double_tap_distance:
- # Close enough to be a double tap
- self.trigger(DoubleTapGesture(event, self.last_tap))
- self.reset_last_tap()
- return
- # Generate a seperate single tap gesture for the last tap,
- # because the lat tap variable is overwritten now
- self.trigger(SingleTapGesture(event, self.last_tap))
- self.last_tap_time = current_time
- self.last_tap = tap
|