1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
// Author: cirakg & claude ai
// Summary: Vertical swipes and drags that scroll a custom view (the Forerunner 70 sends no next/previous-page behaviour for them), scrolling once per gesture.
import Toybox.Lang;
import Toybox.System;
import Toybox.WatchUi;
// A touch gesture can reach a delegate several ways at once: as drag events,
// as a swipe, and as the next/previous-page behaviour. Some watches send only
// the drag. The first one to scroll marks the time; the others arriving within
// DEDUPE_MS are ignored, so one gesture scrolls once. The UP/DOWN buttons
// never mark, so they are only held back right after a touch gesture.
module Gesture {
const DEDUPE_MS = 300;
// A drag shorter than this part of the screen height does not scroll.
const MIN_DRAG_DIVISOR = 8;
// A drag longer than this part still counts as a drag, not a tap.
const SLOP_DIVISOR = 32;
var _scrolledMs as Number? = null;
var _draggedMs as Number? = null;
var _startY as Number? = null;
function _within(since as Number?) as Boolean {
if (since == null) {
return false;
}
var elapsed = System.getTimer() - since;
return elapsed >= 0 && elapsed < DEDUPE_MS;
}
// True right after a touch gesture scrolled: next/previous-page and
// swipe events in this window belong to that gesture.
function recent() as Boolean {
return _within(_scrolledMs);
}
// True right after a drag: a tap arriving now is its end, not a tap.
function tapIgnored() as Boolean {
return _within(_draggedMs);
}
function isVertical(event as WatchUi.SwipeEvent) as Boolean {
var direction = event.getDirection();
return direction == WatchUi.SWIPE_UP || direction == WatchUi.SWIPE_DOWN;
}
// The step for a vertical swipe: 1 (next, swipe up), -1 (previous), or 0
// when this gesture already scrolled.
function swipeStep(event as WatchUi.SwipeEvent) as Number {
if (recent()) {
return 0;
}
_scrolledMs = System.getTimer();
return event.getDirection() == WatchUi.SWIPE_UP ? 1 : -1;
}
// Feed a drag event. At the end of a long enough vertical drag returns
// the signed number of units to scroll (positive = next, finger moved
// up), at least 1 and distance / unit otherwise; 0 for anything else.
function dragStep(event as WatchUi.DragEvent, unit as Number) as Number {
var y = event.getCoordinates()[1];
var type = event.getType();
if (type == WatchUi.DRAG_TYPE_START) {
_startY = y;
return 0;
}
var start = _startY;
if (type != WatchUi.DRAG_TYPE_STOP || start == null) {
return 0;
}
_startY = null;
var height = System.getDeviceSettings().screenHeight;
var distance = start - y;
var length = distance < 0 ? -distance : distance;
if (length > height / SLOP_DIVISOR) {
_draggedMs = System.getTimer();
}
if (length < height / MIN_DRAG_DIVISOR || recent()) {
return 0;
}
_scrolledMs = System.getTimer();
var units = unit > 0 ? length / unit : 1;
units = units < 1 ? 1 : units;
return distance < 0 ? -units : units;
}
}
|