| OLD | NEW |
| 1 Gestures | 1 Gestures |
| 2 ======== | 2 ======== |
| 3 | 3 |
| 4 TODO(ianh): make it possible for a Gesture to time out and cancel even | |
| 5 without having seen a pointer event, to handle double-tap events | |
| 6 | |
| 7 TODO(ianh): even with that, we should keep track of finished-but-valid | |
| 8 candidates so that when double-tap cancels itself, the tap, which was | |
| 9 still valid even though it's done, can be accepted | |
| 10 | |
| 11 ```javascript | 4 ```javascript |
| 12 | 5 typedef PointerID Integer; |
| 13 callback GestureCallback void (Event event); | |
| 14 | 6 |
| 15 dictionary GestureState { | 7 dictionary GestureState { |
| 16 Boolean valid = false; // if true, the event was part of the current gesture | 8 Boolean cancel = true; // if true, then cancel the gesture at this point |
| 17 Boolean forceCommit = false; // if true, the gesture thinks that other gestu
res should give up | 9 Boolean capture = false; // (for pointer-down) if true, then this pointer is r
elevant |
| 10 Boolean choose = false; // if true, the gesture thinks that other gestures sho
uld give up |
| 18 Boolean finished = true; // if true, we're ready for the next gesture to start | 11 Boolean finished = true; // if true, we're ready for the next gesture to start |
| 12 |
| 13 // choose and cancel are mutually exclusive |
| 19 } | 14 } |
| 20 | 15 |
| 21 dictionary SendEventOptions { | 16 dictionary SendEventOptions { |
| 22 Integer? coallesceGroup = null; // when queuing events, only the last event wi
th each group is kept | 17 Integer? coallesceGroup = null; // when queuing events, only the last event wi
th each group is kept |
| 23 Boolean precommit = false; // if true, event should just be sent right away, n
ot queued | 18 Boolean prechoose = false; // if true, event should just be sent right away, n
ot queued |
| 24 } | 19 } |
| 25 | 20 |
| 26 abstract class Gesture { | 21 abstract class Gesture : EventTarget { |
| 27 constructor (); | 22 constructor (EventTarget target); |
| 28 | 23 readonly attribute EventTarget target; |
| 29 attribute GestureCallback callback; | 24 |
| 30 // set by GestureChooser to point to itself | 25 virtual GestureState processEvent(Event event); |
| 31 | 26 // return {} |
| 32 GestureState processEvent(EventTarget target, Event event); | 27 virtual void choose(); // called by GestureManager // make sure to call superc
lass choose() before |
| 33 // - if this.ready=true: | 28 // - assert: this.active == true |
| 34 // - clear the sendEvent() buffer | 29 // - assert: this.chosen == false |
| 35 // - set this.accepted = false | 30 // - set this.chosen = true |
| 36 // - let returnValue = this.processEventInternal(...) | 31 // - if there are any buffered events, dispatch them on this |
| 37 // - if this.discarding: | 32 virtual void cancel(); // called by GestureManager // make sure to call superc
lass cancel() after |
| 38 // - assert: returnValue.valid == false | 33 // - set active and chosen to false, clear the event buffer |
| 39 // - if returnValue.valid == false | 34 |
| 40 // - assert: returnValue.forceCommit == false | 35 readonly attribute Boolean ready; // last event, we were finished |
| 41 // - if !returnValue.valid, then: | 36 readonly attribute Boolean active; // we have not yet been canceled since we l
ast captured a pointer |
| 42 // - clear the sendEvent() buffer | 37 readonly attribute Boolean chosen; // we're the only possible gesture at this
point |
| 43 // - set this.accepted = false | 38 |
| 44 // - set this.canceled = !returnValue.valid | 39 // !ready && !active => we're discarding events until the user gets to a state
where a new gesture can begin |
| 45 // - set this.ready = returnValue.finished | 40 // active && !chosen => we're collecting events until no other gesture is vali
d, or until we take command |
| 46 // - set this.discarding = !returnValue.valid && !returnValue.finished | |
| 47 // - set this.active = returnValue.valid && !returnValue.finished | |
| 48 // - return returnValue | |
| 49 | |
| 50 readonly attribute Boolean canceled; // defaults to false | |
| 51 // true if either the last time processEvent was invoked, valid was | |
| 52 // false, or, we have been cancel()ed | |
| 53 | |
| 54 readonly attribute Boolean ready; // defaults to true | |
| 55 // true if the last time processEvent was invoked, the gesture was | |
| 56 // over | |
| 57 | |
| 58 readonly attribute Boolean discarding; // defaults to false | |
| 59 // true if the last time processEvent was invoked, valid was false | |
| 60 // and finished was false, or, we have been cancel()ed | |
| 61 // (aka canceled && !ready) | |
| 62 | |
| 63 readonly attribute Boolean active; // defaults to false | |
| 64 // true if the last time processEvent was invoked, valid was true | |
| 65 // and finished was false, and we haven't been cancel()ed | |
| 66 // (aka !canceled && !ready) | |
| 67 | |
| 68 readonly attribute Boolean accepted; // defaults to false | |
| 69 // true accept() was called and we haven't been cancel()ed since | |
| 70 | |
| 71 void accept(); | |
| 72 // assert: this.canceled == false | |
| 73 // set accepted = true | |
| 74 // send the buffered gesture events to the callback | |
| 75 // - call this immediately after getting a positive result from | |
| 76 // processEvent() | |
| 77 | |
| 78 virtual void cancel(); | |
| 79 // called to indicate that this gesture isn't going to be chosen, | |
| 80 // or if it was chosen, that it is finished | |
| 81 // - assert: this.canceled == false | |
| 82 // - set this.canceled = true | |
| 83 // - set this.discarding = !this.ready | |
| 84 // - set this.active = false | |
| 85 // - clear the sendEvent() buffer | |
| 86 // - set this.accepted = false | |
| 87 // - descendants may override this if they have more state to drop, | |
| 88 // or if they want to send an event to report that it's canceled, | |
| 89 // especially if this.accepted is true | |
| 90 | |
| 91 virtual void reset(); | |
| 92 // called immediately after the first pointer-down of a possible | |
| 93 // gesture is sent to processEvents() to indicate that the pointer | |
| 94 // wasn't captured so we are to forget anything ever happened (later | |
| 95 // pointer-downs are always captured) | |
| 96 // - set this.canceled = true | |
| 97 // - set this.ready = true | |
| 98 // - set this.discarding = false | |
| 99 // - set this.active = false | |
| 100 // - clear the sendEvent() buffer | |
| 101 // - set this.accepted = false | |
| 102 // - descendants may override this if they have more state to drop | |
| 103 | |
| 104 // internal API: | |
| 105 | |
| 106 virtual GestureState processEventInternal(EventTarget target, Event event); | |
| 107 // descendants override this | |
| 108 // default implementation returns { } (defaults) | |
| 109 // - if this.discarding == false, then: | |
| 110 // - optionally, call sendEvent() to fire gesture-specific | |
| 111 // events | |
| 112 // - as the events are received, they get examined to see if they | |
| 113 // fit the pattern for the gesture; if they do, then return an | |
| 114 // object with valid=true; if more events for this gesture could | |
| 115 // still come in, return finished=false. | |
| 116 // - if you returned valid=false finished=false, then the next call | |
| 117 // to this must not return valid=true | |
| 118 // - doing anything with the event or target other than reading | |
| 119 // state is a contract violation | |
| 120 // - you are allowed to call sendEvent() at any time during a | |
| 121 // processEventInternal() call, or after a call to | |
| 122 // processEventInternal(), assuming that the last such call | |
| 123 // returned either valid=true or finished=true, until the next | |
| 124 // call to processEventInternal() or cancel(). | |
| 125 // - set forceCommit=true on the return value if you are confident | |
| 126 // that this is the gesture the user meant, even if it's possible | |
| 127 // that another gesture is still claiming it's valid (e.g. a long | |
| 128 // press might forceCommit to override a scroll, if the user | |
| 129 // hasn't moved for a while) | |
| 130 // - if you send events, you can set precommit=true to send the | |
| 131 // event even before the gesture has been accepted | |
| 132 // - if you send precommit events, make sure to send corresponding | |
| 133 // "cancel" events if reset() or cancel() are called | |
| 134 | 41 |
| 135 void sendEvent(Event event, SendEventOptions options); | 42 void sendEvent(Event event, SendEventOptions options); |
| 136 // used internally to queue up or send events | 43 // used internally to queue up or send events |
| 137 // - assert: this.discarding == false | 44 // - assert: this.active == true |
| 138 // - assert: options.precommit is false or options.coallesceGroup | 45 // - assert: options.prechoose is false or options.coallesceGroup |
| 139 // is null | 46 // is null |
| 140 // - set event.gesture = this | 47 // - set event.gesture = this |
| 141 // - if this.accepted is true or if options.precommit is true, then | 48 // - if this.chosen is true or if options.prechoose is true, then |
| 142 // send the event straight to the callback | 49 // send the event straight to the callback |
| 143 // - otherwise: | 50 // - otherwise: |
| 144 // - if the buffer has an entry with the same coallesceGroup | 51 // - if the event buffer has an entry with the same |
| 145 // identifier, drop it | 52 // coallesceGroup identifier, drop it |
| 146 // - add the event to the buffer | 53 // - add the event to the event buffer |
| 147 } | 54 } |
| 148 | 55 ``` |
| 149 class GestureChooser : EventTarget { | 56 |
| 150 constructor (EventTarget? target = null, Array<Gesture> candidates = []); | 57 ``Gesture`` objects have an Event buffer, initially empty. Each Event |
| 151 // throws if any of the candidates are active | 58 in this buffer can be associated with a coallesceGroup, which is |
| 152 | 59 identified by integer. |
| 153 readonly attribute EventTarget? target; | 60 |
| 154 void setTarget(EventTarget? target); | 61 When created, ``Gesture`` objects register themselves as pointer-down, |
| 155 | 62 pointer-move, and pointer-up event handlers on their target, with the |
| 156 Array<Gesture> getGestures(); | 63 same event handler. That event handler runs the following steps: |
| 157 void addGesture(Gesture candidate); | 64 - let wasActive = this.active |
| 158 // throw if candidates.active is true | 65 - if this.ready == true, then: |
| 159 void removeGesture(Gesture candidate); | 66 - // reset the state to start a new gesture |
| 160 // if active is true and candidate was the last Gesture in our list | 67 - if this.active == true, then: |
| 161 // to be active, set active and accepted to false | 68 - call application.document.cancelGesture(this) |
| 162 | 69 - set this.active = true |
| 163 // while target is not null and the list of candidates is not empty, | 70 - set this.ready = false |
| 164 // ensures that it is registered as an event listener for | 71 - let returnValue be the result of calling ``processEvent()`` with |
| 165 // pointer-down, pointer-move, and pointer-up events on the target; | 72 the Event object |
| 166 // when the target changes, or when the list of candidates is | 73 - if returnValue.capture == true: |
| 167 // emptied, unregisters itself | 74 - assert: the event is a pointer-down event |
| 168 | 75 - if the event is a pointer-down event: |
| 169 readonly attribute Boolean active; // at least one of the gestures is active (
initially false) | 76 - push this onto the event's return value |
| 170 readonly attribute Boolean accepted; // we accepted a gesture since the last t
ime active was false (initially false) | 77 - if returnValue.cancel == true: |
| 171 | 78 - assert: returnValue.choose == false |
| 172 // internal state: | 79 - if wasActive == true: |
| 173 // /candidates/ is a list of Gesture objects, initially empty | 80 - call application.document.cancelGesture(this) |
| 174 // | 81 - // if wasActive == false, then no need to cancel, since we never added
ourselves |
| 175 // any time one of the pointer events is received: | 82 - if returnValue.cancel == false and this.active == true: |
| 176 // - if it's pointer-down and it's already captured, ignore the | 83 - if wasActive == false or if event is a pointer-down event: |
| 177 // event and skip the remaining steps | 84 - call application.document.addGesture(event, this) |
| 178 // - let captured be a boolean | 85 - if returnValue.choose == true: |
| 179 // - if /candidates/ is empty, then: | 86 - call application.document.chooseGesture(this) |
| 180 // - set captured to false | 87 - set this.ready = returnValue.finished |
| 181 // - if accepted is true, call cancel() on whatever the last | 88 - set this.active = returnValue.valid |
| 182 // accepted candidate was, if any | 89 |
| 183 // - add all the registered Gestures to /candidates/ | 90 Subclasses should override ``processEvent()``: |
| 184 // - otherwise: | 91 - as the events are received, they get examined to see if they |
| 185 // - set captured to true | 92 fit the pattern for the gesture; if they do, then return an |
| 186 // - if it's pointer-down, capture the event | 93 object with valid=true; if more events for this gesture could |
| 187 // - call processEvent() with the event on all the Gestures in | 94 still come in, return finished=false. |
| 188 // /candidates/, collecting their return values (GestureState | 95 - if you returned valid=false finished=false, then the next call |
| 189 // objects) | 96 to this must not return valid=true |
| 190 // - set forcingAccept to false | 97 - doing anything with the event or target other than reading |
| 191 // - set willAccept to null | 98 state is a contract violation |
| 192 // - for each Gesture in /candidates/, in registration order: | 99 - you are allowed to call sendEvent() at any time during a |
| 193 // - if it returned valid==false, then | 100 processEventInternal() call, or after a call to |
| 194 // - if it is our last accepted candidate, then: | 101 processEventInternal(), assuming that the last such call returned |
| 195 // - set this.accepted = false | 102 valid=true, until the next call to processEventInternal() or |
| 196 // - if it returned valid==true: | 103 cancel(). |
| 197 // - if it's pointer-down, then: | 104 - set forceChoose=true on the return value if you are confident |
| 198 // - set captured to true | 105 that this is the gesture the user meant, even if it's possible |
| 199 // - capture the event | 106 that another gesture is still claiming it's valid (e.g. a long |
| 200 // - if this.accepted == true: | 107 press might forceChoose to override a scroll, if the user |
| 201 // - assert: this Gesture is the last accepted candidate | 108 hasn't moved for a while) |
| 202 // - if it returned forceCommit==true then: | 109 - if you send events, you can set prechoose=true to send the |
| 203 // - assert that its accepted attribute is false | 110 event even before the gesture has been chosen |
| 204 // - if forcingAccept is false, then: | 111 - if you send prechoose events, make sure to send corresponding |
| 205 // - set willAccept to this Gesture | 112 "cancel" events if cancel() is called |
| 206 // - set forcingAccept to true | 113 |
| 207 // - otherwise: | 114 ```javascript |
| 208 // - if forcingAccept is false: | 115 dictionary GestureList { |
| 209 // - if willAccept is null: | 116 Array<Gesture> gestures; |
| 210 // - set willAccept to this Gesture | 117 Boolean chosen; |
| 211 // - otherwise: | 118 } |
| 212 // - set willAccept to 'undecided' | 119 |
| 213 // - if it returned finished==true | 120 class GestureManager { |
| 214 // - remove the Gesture from /candidates/ | 121 constructor (EventTarget target); |
| 215 // - if willAccept is set to a Gesture: | 122 readonly attribute EventTarget target; // the ApplicationDocument, normally |
| 216 // - set this.accepted = true | 123 |
| 217 // - call the Gesture's accept() method; this is now the last | 124 void addGesture(Event event, Gesture gesture); |
| 218 // accepted candidate | 125 void cancelGesture(Gesture gesture); |
| 219 // - call cancel() on all the other Gesture objects that returned | 126 void chooseGesture(Gesture gesture); |
| 220 // valid==true | 127 |
| 221 // - if captured is false: | 128 GestureList getActiveGestures(PointerID pointer); |
| 222 // - call reset() on all the gestures in /candidates/, and then | 129 } |
| 223 // let /candidates/ be empty | 130 ``` |
| 224 // - if /candidates/ is now empty, then set active to false; | 131 |
| 225 // otherwise, set active to true | 132 ``GestureManager`` objects have a map of lists of Gesture objects, |
| 226 | 133 keyed on pointer IDs, and with each list associated with a "chosen" |
| 227 } | 134 flag indicating if an entry in the list has already been chosen. |
| 228 | 135 Initially the map is empty. It is exposed by the |
| 136 ``getActiveGestures()`` method, which returns the list and flag. |
| 137 |
| 138 When addGesture() is called with an event and a Gesture, it runs the |
| 139 following steps: |
| 140 - let pointer be the value of the event's pointer field |
| 141 - assert: pointer is an integer |
| 142 - if we already have an entry for pointer: |
| 143 - assert: this Gesture isn't already on the list for pointer |
| 144 - if the list's "chosen" flag is set, then call |
| 145 ``cancelGesture()`` with this Gesture |
| 146 - otherwise, add this Gesture to the list for pointer |
| 147 - otherwise, we don't have an entry for this pointer: |
| 148 - create a list for pointer |
| 149 - add this Gesture to the list for pointer |
| 150 |
| 151 A ``GestureManager``, when created, starts listening to |
| 152 ``pointer-down`` events on its target. The listener acts as follows: |
| 153 - assert: event is a ``pointer-down`` event |
| 154 - let pointer be the value of the event's pointer field |
| 155 - if we have an entry for this pointer, and the "chosen" flag isn't |
| 156 set, and there is just one Gesture in the list, then set the flag |
| 157 on the list and call the Gesture's ``choose()`` method. |
| 158 |
| 159 When ``cancelGesture()`` is called with a Gesture: |
| 160 - for each pointer list: |
| 161 - if the pointer list has this Gesture, remove it |
| 162 - call cancel() on the Gesture |
| 163 - for each pointer list: |
| 164 - if the pointer list has no entries, forget it |
| 165 - if the pointer list has one Gesture and the "chosen" flag isn't |
| 166 set, set it and call that Gesture's ``choose()`` method. |
| 167 |
| 168 When ``chooseGesture()`` is called with a Gesture: |
| 169 - if this Gesture is not active, then return silently |
| 170 // this could happen e.g. if two gestures simultaneously add themselves |
| 171 // and chose themselves for the same pointer-down |
| 172 - let losers be an empty list of Gestures |
| 173 - for each pointer list: |
| 174 - if the pointer list has this Gesture, add all the other Gestures |
| 175 in the list to losers, remove them from the list, and set the |
| 176 "chosen" flag on that list |
| 177 - remove duplicates from losers |
| 178 - call ``cancel()`` on each entry in losers |
| 179 - call ``choose()`` on the Gesture |
| 180 |
| 181 |
| 182 ```javascript |
| 229 class TapGesture : Gesture { | 183 class TapGesture : Gesture { |
| 230 | 184 |
| 231 // internal state: | 185 // internal state: |
| 232 // Integer numButtons = 0; | 186 // Integer numButtons = 0; |
| 233 // Boolean primaryDown = false; | 187 // Boolean primaryDown = false; |
| 234 | 188 |
| 235 virtual Boolean internalProcessEvent(EventTarget target, Event event); | 189 virtual GestureState processEvent(Event event); |
| 190 // - let returnValue = { finished = false } |
| 236 // - if the event is a pointer-down: | 191 // - if the event is a pointer-down: |
| 237 // - increment this.numButtons | 192 // - increment this.numButtons |
| 193 // - set returnValue.capture = true |
| 238 // - otherwise if it is a pointer-up: | 194 // - otherwise if it is a pointer-up: |
| 239 // - assert: this.numButtons > 0 | 195 // - assert: this.numButtons > 0 |
| 240 // - decrement this.numButtons | 196 // - decrement this.numButtons |
| 241 // - if this.discarding == true: | 197 // - if numButtons == 0: |
| 242 // return { valid: false, finished: this.numButtons == 0 } | 198 // - set returnValue.finished = true |
| 199 // - if this.ready == false and this.active == false: |
| 200 // - return returnValue |
| 243 // - if EventTarget isn't an Element: | 201 // - if EventTarget isn't an Element: |
| 244 // - assert: event is a pointer-down | 202 // - assert: event is a pointer-down |
| 245 // - assert: this.numButtons > 0 | 203 // - return returnValue |
| 246 // - return { valid: false, finished: false } | |
| 247 // - if the event is pointer-down: | 204 // - if the event is pointer-down: |
| 248 // - assert: this.numButtons > 0 | 205 // - assert: this.numButtons > 0 |
| 249 // - if it's primary: | 206 // - if it's primary: |
| 250 // - assert: this.ready==true // this is the first press | 207 // - assert: this.ready==true // this is the first press |
| 251 // - this.primaryDown = true | 208 // - this.primaryDown = true |
| 252 // - sendEvent() a tap-down event, with precommit=true | 209 // - sendEvent() a tap-down event, with prechoose=true |
| 253 // - return { valid: true, finished: false } | 210 // - set returnValue.cancel = false |
| 211 // - return returnValue |
| 254 // - otherwise: | 212 // - otherwise: |
| 255 // - if this.ready == false: | 213 // - if this.primaryDown == true and this.active == true: |
| 256 // - // this is a right-click or similar | 214 // - // this is some bogus secondary press that we should have preven
t |
| 257 // - return { valid: false, finished: false } | 215 // // taps from starting until it's finished, but it doesn't invali
date |
| 258 // - otherwise, if this.canceled==false: | 216 // // the existing primary press |
| 259 // - assert: this.active==true | 217 // - set returnValue.cancel = false |
| 260 // - // this is some bogus secondary press that we should ignore | 218 // - return returnValue |
| 261 // // but it doesn't invalidate the existing primary press | |
| 262 // - return { valid true, finished: false } | |
| 263 // - otherwise: | 219 // - otherwise: |
| 264 // - // this is some secondary press but we don't have a first press | 220 // - // this is some secondary press but we don't have a first press |
| 265 // // we have to wait til it's done before we can start a | 221 // // (maybe this is all in the context of a right-click or somethi
ng) |
| 266 // // tap gesture again | 222 // // we have to wait til it's done before we can start a tap gestu
re again |
| 267 // - return { valid: false, finished: false } | 223 // - return returnValue |
| 268 // - otherwise: | 224 // - if the event is pointer-move: |
| 269 // - assert: this.active | 225 // - assert: this.numButtons > 0 |
| 270 // // if we're ready, forcibly the first event we'll see is a pointer-down
, | 226 // - if it's primary: |
| 271 // // so this.ready will never be true here | 227 // - if it hit tests within target's bounding box: |
| 272 // // if we're cancelled, then we won't get to here | 228 // - sendEvent() a tap-move event, with prechoose=true |
| 273 // - if the event is pointer-move: | 229 // - set returnValue.cancel = false |
| 274 // - assert: this.numButtons > 0 | 230 // - return returnValue |
| 275 // // because otherwise we would have lost capture and thus not be gett
ing the events | 231 // - otherwise: |
| 276 // - if it's primary: | 232 // - sendEvent() a tap-cancel event, with prechoose=true |
| 277 // - if it hit tests within target's bounding box: | 233 // - return returnValue |
| 278 // - sendEvent() a tap-move event, with precommit=true | 234 // - otherwise: |
| 279 // - return { valid: true, finished: false } | 235 // - // this is the move of some bogus secondary press |
| 280 // - otherwise: | 236 // // ignore it, but continue listening if we have a primary button do
wn |
| 281 // - sendEvent() a tap-cancel event, with precommit=true | 237 // - if this.primaryDown == true and this.active == true: |
| 282 // - return { valid: false, finished: false } | 238 // - set returnValue.cancel = false |
| 283 // - otherwise: | 239 // - return returnValue |
| 284 // - // this is the move of some bogus secondary press | 240 // - if the event is pointer-up: |
| 285 // // ignore it, but continue listening | 241 // - if it's primary: |
| 286 // - return { valid: true, finished: false } | 242 // - sendEvent() a tap event |
| 287 // - if the event is pointer-up: | 243 // - set this.primaryDown = false |
| 288 // - if it's primary: | 244 // - set returnValue.cancel = false |
| 289 // - sendEvent() a tap event | 245 // - return returnValue |
| 290 // - this.primaryDown = false | 246 // - otherwise: |
| 291 // - return { valid: true, forceCommit: this.numButtons == 0, finished
: this.numButtons == 0 } | 247 // - // this is the 'up' of some bogus secondary press |
| 292 // - otherwise: | 248 // // ignore it, but continue listening for our primary up if necessar
y |
| 293 // - // this is the 'up' of some bogus secondary press | 249 // - if this.primaryDown == true and this.active == true: |
| 294 // // ignore it, but continue listening for our primary up | 250 // - set returnValue.cancel = false |
| 295 // - return { valid: this.primaryDown, finished: this.numButtons == 0
} | 251 // - return returnValue |
| 296 } | 252 } |
| 297 | 253 |
| 298 class LongPressGesture : Gesture { | 254 class LongPressGesture : Gesture { |
| 299 GestureState processEvent(EventTarget target, Event event); | 255 GestureState processEvent(EventTarget target, Event event); |
| 300 // long-tap-start: sent when the primary pointer goes down | 256 // long-tap-start: sent when the primary pointer goes down |
| 301 // long-tap-cancel: sent when cancel(), reset(), or finger goes out of boundin
g box | 257 // long-tap-cancel: sent when cancel()ed or finger goes out of bounding box |
| 302 // long-tap: sent when the primary pointer is released | 258 // long-tap: sent when the primary pointer is released |
| 303 } | 259 } |
| 304 | 260 |
| 305 class DoubleTapGesture : Gesture { | 261 class DoubleTapGesture : Gesture { |
| 306 GestureState processEvent(EventTarget target, Event event); | 262 GestureState processEvent(EventTarget target, Event event); |
| 307 // double-tap-start: sent when the primary pointer goes down the first time | 263 // double-tap-start: sent when the primary pointer goes down the first time |
| 308 // double-tap-cancel: sent when cancel(), reset(), or finger goes out of bound
ing box, or it times out | 264 // double-tap-cancel: sent when cancel()ed or finger goes out of bounding box,
or it times out |
| 309 // double-tap: sent when the primary pointer is released the second time | 265 // double-tap: sent when the primary pointer is released the second time withi
n the timeout |
| 310 } | 266 } |
| 311 | 267 |
| 312 | 268 |
| 313 abstract class ScrollGesture : Gesture { | 269 abstract class ScrollGesture : Gesture { |
| 314 GestureState processEvent(EventTarget target, Event event); | 270 GestureState processEvent(EventTarget target, Event event); |
| 315 // this fires the following events (inertia is a boolean, delta is a float): | 271 // this fires the following events (inertia is a boolean, delta is a float): |
| 316 // scroll-start, with field inertia=false, delta=0; precommit=true | 272 // scroll-start, with field inertia=false, delta=0; prechoose=true |
| 317 // scroll, with fields inertia (is this a simulated scroll from inertia or a
real scroll?), delta (number of pixels to scroll); precommit=true | 273 // scroll, with fields inertia (is this a simulated scroll from inertia or a
real scroll?), delta (number of pixels to scroll); prechoose=true |
| 318 // scroll-end, with field inertia (same), delta=0; precommit=true | 274 // scroll-end, with field inertia (same), delta=0; prechoose=true |
| 319 // scroll-start is fired right away | 275 // scroll-start is fired right away |
| 320 // scroll is sent whenever the primary pointer moves while down | 276 // scroll is sent whenever the primary pointer moves while down |
| 321 // scroll is also sent after the pointer goes back up, based on inertia | 277 // scroll is also sent after the pointer goes back up, based on inertia |
| 322 // scroll-end is sent after the pointer goes back up once the scroll reaches d
elta=0 | 278 // scroll-end is sent after the pointer goes back up once the scroll reaches d
elta=0 |
| 323 // scroll-end is also sent when the gesture is canceled or reset | 279 // scroll-end is also sent when the gesture is canceled or reset |
| 324 // processEvent() returns: | 280 // processEvent() returns: |
| 325 // - valid=true pretty much always so long as there's a primary touch (e.g. n
ot for a right-click) | 281 // - cancel=false pretty much always so long as there's a primary touch (e.g.
not for a right-click) |
| 326 // - forceCommit=true when you travel a certain distance | 282 // - chose=true when you travel a certain distance |
| 327 // - finished=true when the primary pointer goes up | 283 // - finished=true when the primary pointer goes up |
| 328 } | 284 } |
| 329 | 285 |
| 330 class HorizontalScrollGesture : ScrollGesture { } | 286 class HorizontalScrollGesture : ScrollGesture { } |
| 331 // a ScrollGesture giving x-axis scrolling | 287 // a ScrollGesture giving x-axis scrolling |
| 332 | 288 |
| 333 class VerticalScrollGesture : ScrollGesture { } | 289 class VerticalScrollGesture : ScrollGesture { } |
| 334 // a ScrollGesture giving y-axis scrolling | 290 // a ScrollGesture giving y-axis scrolling |
| 335 | 291 |
| 336 | 292 |
| 337 class PanGesture : Gesture { | 293 class PanGesture : Gesture { |
| 338 // similar to ScrollGesture, but with two axes | 294 // similar to ScrollGesture, but with two axes |
| 339 // pan-start, pan, pan-end | 295 // pan-start, pan, pan-end |
| 340 // events have inertia (boolean), dx (float), dy (float) | 296 // events have inertia (boolean), dx (float), dy (float) |
| 341 } | 297 } |
| 342 | 298 |
| 343 | 299 |
| 344 abstract class ZoomGesture : Gesture { | 300 abstract class ZoomGesture : Gesture { |
| 345 GestureState processEvent(EventTarget target, Event event); | 301 GestureState processEvent(EventTarget target, Event event); |
| 346 // zoom-start: sent when we could start zooming (e.g. for pinch-zoom, when two
fingers hit the glass) (precommit) | 302 // zoom-start: sent when we could start zooming (e.g. for pinch-zoom, when two
fingers hit the glass) (prechoose) |
| 347 // zoom-end: sent when cancel()ed after zoom-start, or when the fingers are li
fted (precommit) | 303 // zoom-end: sent when cancel()ed after zoom-start, or when the fingers are li
fted (prechoose) |
| 348 // zoom, with a 'scale' attribute, whose value is a multiple of the scale fact
or at zoom-start | 304 // zoom, with a 'scale' attribute, whose value is a multiple of the scale fact
or at zoom-start |
| 349 // e.g. if the user zooms to 2x, you'd get a bunch of 'zoom' events like scale
=1.0, scale=1.17, ... scale=1.91, scale=2.0 | 305 // e.g. if the user zooms to 2x, you'd get a bunch of 'zoom' events like scale
=1.0, scale=1.17, ... scale=1.91, scale=2.0 |
| 350 } | 306 } |
| 351 | 307 |
| 352 class PinchZoomGesture : ZoomGesture { | 308 class PinchZoomGesture : ZoomGesture { |
| 353 // a ZoomGesture for two-finger-pinch gesture | 309 // a ZoomGesture for two-finger-pinch gesture |
| 354 // zoom is precommit | 310 // zoom is prechoose |
| 355 } | 311 } |
| 356 | 312 |
| 357 class DoubleTapZoomGesture : ZoomGesture { | 313 class DoubleTapZoomGesture : ZoomGesture { |
| 358 // a ZoomGesture for the double-tap-slide gesture | 314 // a ZoomGesture for the double-tap-slide gesture |
| 359 // when the slide starts, forceCommit | 315 // when the slide starts, forceChoose |
| 360 } | 316 } |
| 361 | 317 |
| 362 | 318 |
| 363 class PanAndZoomGesture : Gesture { | 319 class PanAndZoomGesture : Gesture { |
| 364 GestureState processEvent(EventTarget target, Event event); | 320 GestureState processEvent(EventTarget target, Event event); |
| 365 // manipulate-start (precommit) | 321 // manipulate-start (prechoose) |
| 366 // manipulate: (precommit) | 322 // manipulate: (prechoose) |
| 367 // panX, panY: pixels | 323 // panX, panY: pixels |
| 368 // scaleX, scaleY: a multiplier of the scale at manipulate-start | 324 // scaleX, scaleY: a multiplier of the scale at manipulate-start |
| 369 // rotation: turns | 325 // rotation: turns |
| 370 // manipulate-end (precommit) | 326 // manipulate-end (prechoose) |
| 371 } | 327 } |
| 372 | 328 |
| 373 | 329 |
| 374 abstract class FlingGesture : Gesture { | 330 abstract class FlingGesture : Gesture { |
| 375 GestureState processEvent(EventTarget target, Event event); | 331 GestureState processEvent(EventTarget target, Event event); |
| 376 // fling-start: when the gesture begins (precommit) | 332 // fling-start: when the gesture begins (prechoose) |
| 377 // fling-move: while the user is directly dragging the element (has delta attr
ibute with the distance from fling-start) (precommit) | 333 // fling-move: while the user is directly dragging the element (has delta attr
ibute with the distance from fling-start) (prechoose) |
| 378 // fling: the user has released the pointer and the decision is it was in fact
flung | 334 // fling: the user has released the pointer and the decision is it was in fact
flung |
| 379 // fling-cancel: cancel(), or the user has released the pointer and the decisi
on is it was not flung (precommit) | 335 // fling-cancel: cancel(), or the user has released the pointer and the decisi
on is it was not flung (prechoose) |
| 380 // fling-end: cancel(), reset(), or after fling or fling-cancel (precommit) | 336 // fling-end: cancel(), or after fling or fling-cancel (prechoose) |
| 381 } | 337 } |
| 382 | 338 |
| 383 class FlingLeftGesture : FlingGesture { } | 339 class FlingLeftGesture : FlingGesture { } |
| 384 class FlingRightGesture : FlingGesture { } | 340 class FlingRightGesture : FlingGesture { } |
| 385 class FlingUpGesture : FlingGesture { } | 341 class FlingUpGesture : FlingGesture { } |
| 386 class FlingDownGesture : FlingGesture { } | 342 class FlingDownGesture : FlingGesture { } |
| 387 | 343 |
| 388 ``` | 344 ``` |
| OLD | NEW |