Clean up gesture handling

All the gnarly direction detection for swipes is moved into touch.pyj
and the handlers just need to check the event type (except for flow mode
where we really want to match finger movement).
This commit is contained in:
Kovid Goyal 2023-06-11 09:30:27 +05:30
parent fdb68a1613
commit dcfc477c28
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 75 additions and 36 deletions

View File

@ -23,6 +23,7 @@ from __python__ import bound_methods, hash_literals
from dom import set_css
from range_utils import wrap_range, unwrap
from read_book.cfi import scroll_to as cfi_scroll_to
from read_book.touch import GESTURE
from read_book.globals import current_spine_item, get_boss, rtl_page_progression, ltr_page_progression
from read_book.settings import opts
from read_book.viewport import line_height, rem_size, scroll_viewport
@ -536,7 +537,9 @@ def start_drag_scroll(delta):
def handle_gesture(gesture):
flick_animator.stop()
if gesture.type is 'swipe':
if gesture.type is GESTURE.flick_block_forward or gesture.type is GESTURE.flick_block_backward:
flick_animator.start(gesture)
elif gesture.type.startsWith('swipe_') and gesture.type.endsWith('_in_progress'):
if gesture.points.length > 1 and not gesture.is_held:
delta = gesture.points[-2] - gesture.points[-1]
if Math.abs(delta) >= 1:
@ -556,13 +559,11 @@ def handle_gesture(gesture):
# In horizontal modes, just move by the delta.
else:
scroll_viewport.scroll_by(delta, 0)
if not gesture.active and not gesture.is_held:
flick_animator.start(gesture)
elif gesture.type is 'prev-page':
elif gesture.type is GESTURE.back_zone_tap:
# should flip = False - previous is previous whether RTL or LTR.
# flipping of this command is handled higher up
scroll_by_page(-1, False)
elif gesture.type is 'next-page':
elif gesture.type is GESTURE.forward_zone_tap:
# should flip = False - next is next whether RTL or LTR.
# flipping of this command is handled higher up
scroll_by_page(1, False)

View File

@ -9,6 +9,7 @@ from range_utils import (
all_annots_in_selection, highlight_associated_with_selection, last_span_for_crw,
reset_highlight_counter, select_crw, unwrap_all_crw, unwrap_crw, wrap_text_in_range
)
from read_book.touch import GESTURE
from read_book.cfi import cfi_for_selection, range_from_cfi
from read_book.extract import get_elements
from read_book.find import (
@ -315,13 +316,13 @@ class IframeBoss:
self.auto_scroll_action('toggle')
def handle_gesture(self, gesture):
if gesture.type is 'show-chrome':
if gesture.type is GESTURE.control_zone_tap or gesture.type is GESTURE.two_finger_tap:
self.send_message('show_chrome')
elif gesture.type is 'two-finger-tap':
self.send_message('show_chrome')
elif gesture.type is 'pinch':
self.send_message('bump_font_size', increase=gesture.direction is 'out')
elif gesture.type is 'long-tap':
elif gesture.type is GESTURE.pinch_in:
self.send_message('bump_font_size', increase=False)
elif gesture.type is GESTURE.pinch_out:
self.send_message('bump_font_size', increase=True)
elif gesture.type is GESTURE.long_tap:
self.handle_long_tap(gesture)
else:
self._handle_gesture(gesture)

View File

@ -32,6 +32,7 @@ from read_book.cfi import (
scroll_to as cfi_scroll_to
)
from read_book.globals import current_spine_item, get_boss, rtl_page_progression
from read_book.touch import GESTURE
from read_book.settings import opts
from read_book.viewport import scroll_viewport, line_height, rem_size, get_unit_size_in_pixels
from utils import (
@ -808,19 +809,20 @@ def handle_shortcut(sc_name, evt):
def handle_gesture(gesture):
if gesture.type is 'swipe':
if gesture.axis is 'vertical':
if not gesture.active:
get_boss().send_message('next_section', forward=gesture.direction is 'up')
else:
if not gesture.active or gesture.is_held:
scroll_by_page(gesture.direction is 'right', True, flip_if_rtl_page_progression=True)
# Gesture progression direction is determined in the gesture code,
# don't set flip_if_rtl_page_progression=True here.
elif gesture.type is 'prev-page':
scroll_by_page(True, opts.paged_taps_scroll_by_screen, flip_if_rtl_page_progression=False)
elif gesture.type is 'next-page':
scroll_by_page(False, opts.paged_taps_scroll_by_screen, flip_if_rtl_page_progression=False)
if gesture.type is GESTURE.flick_block_forward:
get_boss().send_message('next_section', forward=True)
elif gesture.type is GESTURE.flick_block_backward:
get_boss().send_message('next_section', forward=False)
elif gesture.type is GESTURE.flick_inline_forward or gesture.type is GESTURE.swipe_inline_forward_hold:
scroll_by_page(False, True)
elif gesture.type is GESTURE.flick_inline_backward or gesture.type is GESTURE.swipe_inline_backward_hold:
scroll_by_page(True, True)
elif gesture.type is GESTURE.back_zone_tap:
scroll_by_page(True, opts.paged_taps_scroll_by_screen)
elif gesture.type is GESTURE.forward_zone_tap:
scroll_by_page(False, opts.paged_taps_scroll_by_screen)
anchor_funcs = {

View File

@ -2,6 +2,7 @@
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
from gettext import gettext as _
from read_book.globals import get_boss, ltr_page_progression, ui_operations
from read_book.settings import opts
from read_book.viewport import get_unit_size_in_pixels, scroll_viewport
@ -11,6 +12,31 @@ TAP_THRESHOLD = 8 # pixels
SWIPE_THRESHOLD = 64 # pixels
TAP_LINK_THRESHOLD = 5 # pixels
PINCH_THRESHOLD = 20 # pixels
GESTURE_NAMES = {
'back_zone_tap': _('Tap on back zone'),
'forward_zone_tap': _('Tap on forward zone'),
'control_zone_tap': _('Tap in the controls zone'),
'long_tap': _('Long tap'),
'two_finger_tap': _('Two finger tap'),
'pinch_in': _('Pinch in'),
'pinch_out': _('Pinch out'),
'flick_inline_backward': _('Flick in writing direction, backwards'),
'flick_inline_forward': _('Flick in writing direction, forwards'),
'flick_block_backward': _('Flick perpendicular to writing direction, backwards'),
'flick_block_forward': _('Flick perpendicular to writing direction, forwards'),
'swipe_inline_backward_in_progress': _('Swipe in writing direction, backwards, in-progress'),
'swipe_inline_forward_in_progress': _('Swipe in writing direction, forwards, in-progress'),
'swipe_block_backward_in_progress': _('Swipe perpendicular to writing direction, backwards, in-progress'),
'swipe_block_forward_in_progress': _('Swipe perpendicular to writing direction, forwards, in-progress'),
'swipe_inline_backward_hold': _('Swipe in writing direction, backwards and hold'),
'swipe_inline_forward_hold': _('Swipe in writing direction, forwards and hold'),
'swipe_block_backward_hold': _('Swipe perpendicular to writing direction, backwards and hold'),
'swipe_block_forward_hold': _('Swipe perpendicular to writing direction, forwards and hold'),
}
GESTURE = {k:k for k in Object.keys(GESTURE_NAMES)}
GESTURE.tap = 'tap'
GESTURE.swipe = 'swipe'
GESTURE.pinch = 'pinch'
gesture_id = 0
@ -50,7 +76,7 @@ def interpret_single_gesture(touch, gesture_id):
max_y_displacement = max_displacement(touch.viewport_y)
ans = {'active':touch.active, 'is_held':touch.is_held, 'id':gesture_id, 'start_time': touch.ctime}
if max(max_x_displacement, max_y_displacement) < TAP_THRESHOLD:
ans.type = 'tap'
ans.type = GESTURE.tap
ans.viewport_x = touch.viewport_x[0]
ans.viewport_y = touch.viewport_y[0]
return ans
@ -60,7 +86,7 @@ def interpret_single_gesture(touch, gesture_id):
delta_y = abs(touch.viewport_y[-1] - touch.viewport_y[0])
max_disp = max(delta_y, delta_x)
if max_disp > SWIPE_THRESHOLD and min(delta_x, delta_y)/max_disp < 0.35:
ans.type = 'swipe'
ans.type = GESTURE.swipe
ans.axis = 'vertical' if delta_y > delta_x else 'horizontal'
ans.points = pts = touch.viewport_y if ans.axis is 'vertical' else touch.viewport_x
ans.times = touch.mtimes
@ -82,7 +108,7 @@ def interpret_double_gesture(touch1, touch2, gesture_id):
max_y_displacement1 = max_displacement(touch1.viewport_y)
max_y_displacement2 = max_displacement(touch2.viewport_y)
if max(max_x_displacement1, max_y_displacement1) < TAP_THRESHOLD and max(max_x_displacement2, max_y_displacement2) < TAP_THRESHOLD:
ans.type = 'two-finger-tap'
ans.type = GESTURE.two_finger_tap
ans.viewport_x1 = touch1.viewport_x[0]
ans.viewport_y1 = touch1.viewport_y[0]
ans.viewport_x2 = touch2.viewport_x[0]
@ -92,7 +118,7 @@ def interpret_double_gesture(touch1, touch2, gesture_id):
final_distance = Math.sqrt((touch1.viewport_x[-1] - touch2.viewport_x[-1])**2 + (touch1.viewport_y[-1] - touch2.viewport_y[-1])**2)
distance = abs(final_distance - initial_distance)
if distance > PINCH_THRESHOLD:
ans.type = 'pinch'
ans.type = GESTURE.pinch
ans.direction = 'in' if final_distance < initial_distance else 'out'
ans.distance = distance
return ans
@ -255,42 +281,51 @@ class BookTouchHandler(TouchHandler):
TouchHandler.__init__(self)
def handle_gesture(self, gesture):
gesture.from_side_margin = self.for_side_margin
if gesture.type is 'tap':
if gesture.type is GESTURE.tap:
if gesture.is_held:
if not self.for_side_margin and not self.handled_tap_hold and window.performance.now() - gesture.start_time >= HOLD_THRESHOLD:
self.handled_tap_hold = True
gesture.type = 'long-tap'
gesture.type = GESTURE.long_tap
get_boss().handle_gesture(gesture)
return
if not gesture.active:
if self.for_side_margin or not tap_on_link(gesture):
inch = inch_in_pixels()
if gesture.viewport_y < min(100, scroll_viewport.height() / 4):
gesture.type = 'show-chrome'
gesture.type = GESTURE.control_zone_tap
else:
limit = inch
# default, books that go left to right.
if ltr_page_progression() and not opts.reverse_page_turn_zones:
if gesture.viewport_x < min(limit, scroll_viewport.width() / 4):
gesture.type = 'prev-page'
gesture.type = GESTURE.back_zone_tap
else:
gesture.type = 'next-page'
gesture.type = GESTURE.forward_zone_tap
# We swap the sizes in RTL mode, so that going to the next page is always the bigger touch region.
else:
# The "going back" area should not be more than limit units big,
# even if 1/4 of the scroll viewport is more than limit units.
# Checking against the larger of the width minus the limit units and 3/4 of the width will accomplish that.
if gesture.viewport_x > max(scroll_viewport.width() - limit, scroll_viewport.width() * (3/4)):
gesture.type = 'prev-page'
gesture.type = GESTURE.back_zone_tap
else:
gesture.type = 'next-page'
if gesture.type is 'pinch':
gesture.type = GESTURE.forward_zone_tap
elif gesture.type is GESTURE.pinch:
if gesture.active:
return
if gesture.type is 'two-finger-tap':
gesture.type = GESTURE.pinch_in if gesture.direction is 'in' else GESTURE.pinch_out
elif gesture.type is GESTURE.two_finger_tap:
if gesture.active:
return
elif gesture.type is 'swipe':
backward_dir = 'down' if gesture.axis is 'vertical' else ('right' if ltr_page_progression() else 'left')
direction = 'backward' if gesture.direction is backward_dir else 'forward'
inline_dir = 'vertical' if scroll_viewport.vertical_writing_mode else 'horizontal'
axis = 'inline' if gesture.axis is inline_dir else 'block'
if gesture.active:
gesture.type = GESTURE[f'swipe_{axis}_{direction}' + ('_hold' if gesture.is_held else '_in_progress')]
elif not gesture.is_held:
gesture.type = GESTURE[f'flick_{axis}_{direction}']
if self.for_side_margin:
ui_operations.forward_gesture(gesture)
else: