Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: sky/specs/gestures.md

Issue 858353003: Specs: Gestures API Mark II - on the path to supporting gestures that fire events after they're fin… (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | sky/specs/idl.md » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 Gestures 1 Gestures
2 ======== 2 ========
3 3
4 ```javascript 4 ```javascript
5 5
6 callback GestureCallback void (Event event); 6 callback GestureCallback void (Event event);
7 7
8 dictionary GestureState {
9 Boolean valid = false; // if true, the event was part of the current gesture
10 Boolean finished = true; // if true, we're ready for the next gesture to start
11 }
12
8 abstract class Gesture { 13 abstract class Gesture {
9 constructor (); 14 constructor ();
10 15
11 // Gestures cycle through states: 16 Boolean processEvent(EventTarget target, Event event);
12 // - idle: nothing is going on (active, accepted, and discarding 17 // - if this.ready=true, clear the sendEvent() buffer and forget
13 // are false). 18 // the last accept() callback, if any.
14 // - buffering: the GestureChooser is passing in some events, but 19 // - let returnValue = this.processEventInternal(...)
15 // hasn't yet committed to using this Gesture, and this Gesture 20 // - if this.discarding:
16 // hasn't yet decided that this set of events isn't interesting 21 // - assert: returnValue.valid == false
17 // (active is true, accepted is false, discarding is false). 22 // - if !returnValue.valid, then clear the sendEvent() buffer and
18 // - forwarding: this Gesture is still interesting and the 23 // forget the last accept() callback, if any
19 // GestureChooser has decided to use this Gesture so events are 24 // - set this.ready = returnValue.finished
20 // being sent along (active is true, accepted is true, discarding 25 // - set this.canceled = !returnValue.valid
21 // is false). 26 // - set this.discarding = !returnValue.valid && !returnValue.finished
22 // - discarding: this Gesture got cancelled or didn't match the 27 // - set this.active = returnValue.valid && !returnValue.finished
23 // pattern (active is true, accepted is false, discarding is 28 // - return returnValue.valid
24 // true).
25 29
26 // TODO(ianh): Need to handle gestures that want to send events 30 readonly attribute Boolean active; // defaults to false
27 // beyond the end of the gesture, e.g. inertia in scrolling. In that 31 // true if the last time processEvent was invoked, valid was true
28 // mode, gestures are sending events but are simultaneously no 32 // and finished was false, and we haven't been cancel()ed
29 // longer "active"...
30 33
31 Boolean processEvent(EventTarget target, Event event); 34 readonly attribute Boolean canceled; // defaults to false
32 // as the events are received, they get examined to see if they fit 35 // true if either the last time processEvent was invoked, valid was
33 // the pattern for the gesture; if they do, then returns true, else, 36 // false, or, we have been cancel()ed
34 // returns false 37
35 // - returning true after false has been returned is a contract 38 readonly attribute Boolean discarding; // defaults to false
36 // violation unless active became false in between 39 // true if the last time processEvent was invoked, valid was false
37 // - manipulating the event is a contract violation 40 // and finished was false, and we haven't been cancel()ed
38 // 41
39 // TODO(ianh): replace processEvent()'s return value with an enum: 42 readonly attribute Boolean ready; // defaults to true
40 // - acceptable (true and active is true) 43 // true if the last time processEvent was invoked, the gesture was
41 // - discarding (false but active is still true) 44 // over, or, we have been cancel()ed
42 // - finished (false and active is now false)
43 // in such a world, the contract would be that you can't return
44 // 'acceptable' after returning 'discarding' without first returning
45 // 'finished'
46 45
47 void accept(GestureCallback callback); 46 void accept(GestureCallback callback);
48 // set accepted to true, send the buffered gesture events to 47 // assert: this.canceled == false
49 // callback, and use that callback for all future Gesture events 48 // remember the giver accept callback, and send the buffered gesture
50 // until the gesture is complete 49 // events to that callback
51 // - call this immediately after getting a positive result from 50 // - call this immediately after getting a positive result from
52 // processEvent() 51 // processEvent()
53 52
53 virtual void cancel();
54 // set active=false, canceled=true, discarding=false, ready=false
55 // clear the sendEvent() buffer and forget the last accept()
56 // callback, if any
57 // descendants may override this if they have more state to drop
58
54 // internal API: 59 // internal API:
55 // void sendEvent(Event event) 60
56 // - assert: active is true, discarding is false 61 virtual GestureState processEventInternal(EventTarget target, Event event);
62 // descendants override this
63 // default implementation returns { } (defaults)
64 // - if this.discarding == false, then:
65 // - optionally, call sendEvent() to fire gesture-specific
66 // events
67 // - as the events are received, they get examined to see if they
68 // fit the pattern for the gesture; if they do, then return an
69 // object with valid=true; if more events for this gesture could
70 // still come in, return finished=false.
71 // - if you returned valid=false finished=false, then the next call
72 // to this must not return valid=true
73 // - doing anything with the event or target other than reading
74 // state is a contract violation
75 // - you are allowed to call sendEvent() at any time during a
76 // processEventInternal() call, or between calls to
77 // processEventInternal() assuming that the last such call
78 // returned either valid=true or finished=true.
79
80 void sendEvent(Event event);
81 // used internally to queue up or send events
82 // - assert: this.discarding == false
57 // - if accepted is true, then send the event straight to the 83 // - if accepted is true, then send the event straight to the
58 // callback 84 // callback
59 // - otherwise, add it to the buffer 85 // - otherwise, add it to the buffer
60 //
61 // void discard()
62 // - throw away the buffer, set discarding to true and accepted to
63 // false
64
65 readonly attribute Boolean active; // not idle (buffering, forwarding, or disc arding)
66 readonly attribute Boolean accepted; // true if active and accept() has been c alled (forwarding or discarding)
67 readonly attribute Boolean discarding; // true if active and processEvent() ha s returned false (discarding)
68 // 'active' is currently part of the contract between Gesture and GestureChoos er (the other two are not)
69
70 // active can be true even if processEvent() returned false; this is
71 // the discarding state. It means that the Gesture isn't sending any
72 // more events, but that the pointers haven't yet reached a state in
73 // which a new touch could begin. For example, a Tap gesture where
74 // the finger has gone out of the bounding box can't be retriggered
75 // until the finger is lifted.
76 86
77 } 87 }
78 88
79 class GestureChooser : EventTarget { 89 class GestureChooser : EventTarget {
80 constructor (EventTarget? target = null, Array<Gesture> candidates = []); 90 constructor (EventTarget? target = null, Array<Gesture> candidates = []);
81 // throws if any of the candidates are active 91 // throws if any of the candidates are active
82 92
83 readonly attribute EventTarget? target; 93 readonly attribute EventTarget? target;
84 void setTarget(EventTarget? target); 94 void setTarget(EventTarget? target);
85 95
86 Array<Gesture> getGestures(); 96 Array<Gesture> getGestures();
87 void addGesture(Gesture candidate); 97 void addGesture(Gesture candidate);
88 // throw if candidates.active is true 98 // throw if candidates.active is true
89 void removeGesture(Gesture candidate); 99 void removeGesture(Gesture candidate);
90 // if active is true and candidate was the last Gesture in our list 100 // if active is true and candidate was the last Gesture in our list
91 // to be active, set active and accepted to false 101 // to be active, set active and accepted to false
92 102
93 // while target is not null and the list of candidates is not empty, 103 // while target is not null and the list of candidates is not empty,
94 // ensures that it is registered as an event listener for 104 // ensures that it is registered as an event listener for
95 // pointer-down, pointer-move, and pointer-up events on the target; 105 // pointer-down, pointer-move, and pointer-up events on the target;
96 // when the target changes, or when the list of candidates is 106 // when the target changes, or when the list of candidates is
97 // emptied, unregisters itself 107 // emptied, unregisters itself
98 108
99 readonly attribute Boolean active; // at least one of the gestures is active ( initially false) 109 readonly attribute Boolean active; // at least one of the gestures is active ( initially false)
100 readonly attribute Boolean accepted; // we accepted a gesture since the last t ime active was false (initially false) 110 readonly attribute Boolean accepted; // we accepted a gesture since the last t ime active was false (initially false)
111
101 // any time one of the pointer events is received: 112 // any time one of the pointer events is received:
102 // - if it's pointer-down and it's already captured, ignore the 113 // - if it's pointer-down and it's already captured, ignore the
103 // event; otherwise: 114 // event; otherwise:
104 // - let /candidates/ be a list of gestures, initially empty 115 // - let /candidates/ be a list of Gestures, initially empty
105 // - if none of the registered gestures are active, then add all of 116 // - if all of the registered Gestures have ready==true, then add
106 // them to /candidates/ otherwise, add all the active ones to 117 // all of them to /candidates/; otherwise, add all the Gestures
107 // /candidates/ 118 // with ready==false to /candidates/
108 // - call processEvent() with the event on all the Gestures in 119 // - call processEvent() with the event on all the Gestures in
109 // /candidates/ 120 // /candidates/
110 // - if it's pointer-down and at least one Gesture returned true, 121 // - if it's pointer-down then:
111 // then capture the event 122 // - if at least one Gesture returned true, then capture the
123 // event
124 // - else send cancel() to all the gestures in /candidates/.
112 // - if accepted is false, and exactly one of the processEvent() 125 // - if accepted is false, and exactly one of the processEvent()
113 // methods returned true, then set accepted to true and call that 126 // methods returned true, then set accepted to true and call that
114 // Gesture's accept() method, passing it a method that fires the 127 // Gesture's accept() method, passing it a method that fires the
115 // provided event on the current target (if not null) 128 // provided event on the current target (if not null)
116 // - if all the processEvent() methods returned false, and all the 129 // - if all the registered Gestures are now ready==true (regardless
117 // Gestures are no longer active, then set active and accepted to 130 // of the return values), then set active and accepted to false;
118 // false; otherwise, set active to true 131 // otherwise, set active to true
132
119 } 133 }
120 134
121 class TapGesture : Gesture { 135 class TapGesture : Gesture {
122 Boolean processEvent(EventTarget target, Event event); 136
123 // if discarding is true: 137 // internal state:
124 // - if the event is a primary pointer-up, set active, accepted, and 138 // Integer numButtons = 0;
125 // discarding to false, and return false 139 // Boolean primaryDown = false;
126 // - otherwise, just return false 140
127 // if EventTarget isn't an Element: 141 virtual Boolean internalProcessEvent(EventTarget target, Event event);
128 // - set active to true, discard(), and return false 142 // - if the event is a pointer-down:
129 // if the event is pointer-down: 143 // - increment this.numButtons
130 // - if it's primary: 144 // - otherwise if it is a pointer-up:
131 // - assert: active is false 145 // - assert: this.numButtons > 0
132 // - sendEvent() a tap-down event 146 // - decrement this.numButtons
133 // - set active to true and return true 147 // - if this.discarding == true:
134 // - otherwise, if we're active: 148 // return { valid: false, finished: this.numButtons == 0 }
135 // - return true 149 // - if EventTarget isn't an Element:
136 // - otherwise: 150 // - assert: event is a pointer-down
137 // - return false 151 // - assert: this.numButtons > 0
138 // if the event is pointer-move: 152 // - return { valid: false, finished: false }
139 // - if it's primary: 153 // - if the event is pointer-down:
140 // - if it hit tests within target's bounding box: 154 // - assert: this.numButtons > 0
141 // - sendEvent() a tap-move event 155 // - if it's primary:
142 // - return true 156 // - assert: this.ready==true // this is the first press
157 // - this.primaryDown = true
158 // - sendEvent() a tap-down event
159 // - return { valid: true, finished: false }
160 // - otherwise:
161 // - if this.ready == false:
162 // - // this is a right-click or similar
163 // - return { valid: false, finished: false }
164 // - otherwise, if this.canceled==false:
165 // - assert: this.active==true
166 // - // this is some bogus secondary press that we should ignore
167 // // but it doesn't invalidate the existing primary press
168 // - return { valid true, finished: false }
169 // - otherwise:
170 // - // this is some secondary press but we don't have a first press
171 // // we have to wait til it's done before we can start a
172 // // tap gesture again
173 // - return { valid: false, finished: false }
174 // - otherwise:
175 // - assert: this.active
176 // // if we're ready, forcibly the first event we'll see is a pointer-down ,
177 // // so this.ready will never be true here
178 // // if we're cancelled, then we won't get to here
179 // - if the event is pointer-move:
180 // - assert: this.numButtons > 0
181 // // because otherwise we would have lost capture and thus not be gett ing the events
182 // - if it's primary:
183 // - if it hit tests within target's bounding box:
184 // - sendEvent() a tap-move event
185 // - return { valid: true, finished: false }
186 // - otherwise:
187 // - sendEvent() a tap-cancel event
188 // - return { valid: false, finished: false }
143 // - otherwise: 189 // - otherwise:
144 // - sendEvent() a tap-cancel event 190 // - // this is the move of some bogus secondary press
145 // - discard() and return false 191 // // ignore it, but continue listening
146 // - otherwise, if we're active: 192 // - return { valid: true, finished: false }
147 // - return true 193 // - if the event is pointer-up:
148 // - otherwise: 194 // - if it's primary:
149 // - return false 195 // - sendEvent() a tap event
150 // if the event is pointer-up: 196 // - this.primaryDown = false
151 // - if it's primary: 197 // - return { valid: true, finished: this.numButtons == 0 }
152 // - sendEvent() a tap event 198 // - otherwise:
153 // - set accepted and active to false, discard(), and return false 199 // - // this is the 'up' of some bogus secondary press
154 // - otherwise, if we're active: 200 // // ignore it, but continue listening for our primary up
155 // - return true 201 // - return { valid: this.primaryDown, finished: this.numButtons == 0 }
156 // - otherwise:
157 // - return false
158 } 202 }
159 203
160 class ScrollGesture : Gesture { 204 class ScrollGesture : Gesture {
161 Boolean processEvent(EventTarget target, Event event); 205 Boolean processEvent(EventTarget target, Event event);
162 // this fires the following events: 206 // this fires the following events:
163 // TODO(ianh): fill this in 207 // TODO(ianh): fill this in
164 } 208 }
165 209
166 ``` 210 ```
OLDNEW
« no previous file with comments | « no previous file | sky/specs/idl.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698