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

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

Issue 924393004: Specs: strip @nonnull annotations since they're too verbose (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 10 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/pointer.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 ```dart 4 ```dart
5 SKY MODULE 5 SKY MODULE
6 <!-- part of dart:sky --> 6 <!-- part of dart:sky -->
7 7
8 <script> 8 <script>
9 abstract class GestureEvent extends Event { 9 abstract class GestureEvent extends Event {
10 Gesture _gesture; 10 Gesture _gesture;
11 Gesture get gesture => _gesture; 11 Gesture get gesture => _gesture;
12 } 12 }
13 13
14 class GestureState { 14 class GestureState {
15 @nonnull bool cancel = true; // if true, then cancel the gesture at this point 15 bool cancel = true; // if true, then cancel the gesture at this point
16 @nonnull bool capture = false; // (for PointerDownEvent) if true, then this po inter is relevant 16 bool capture = false; // (for PointerDownEvent) if true, then this pointer is relevant
17 @nonnull bool choose = false; // if true, the gesture thinks that other gestur es should give up 17 bool choose = false; // if true, the gesture thinks that other gestures should give up
18 @nonnull bool finished = true; // if true, we're ready for the next gesture to start 18 bool finished = true; // if true, we're ready for the next gesture to start
19 // choose and cancel are mutually exclusive 19 // choose and cancel are mutually exclusive
20 } 20 }
21 21
22 class BufferedEvent { 22 class BufferedEvent {
23 const BufferedEvent(this.event, this.coallesceGroup); 23 const BufferedEvent(this.event, this.coallesceGroup);
24 final @nonnull GestureEvent event; 24 final GestureEvent event;
25 final int coallesceGroup; 25 final int coallesceGroup;
26 } 26 }
27 27
28 abstract class Gesture extends EventTarget { 28 abstract class Gesture extends EventTarget {
29 Gesture(this.target) : super() { 29 Gesture(this.target) : super() {
30 target.events.where((event) => event is PointerDownEvent || 30 target.events.where((event) => event is PointerDownEvent ||
31 event is PointerMovedEvent || 31 event is PointerMovedEvent ||
32 event is PointerUpEvent).listen(_handler); 32 event is PointerUpEvent).listen(_handler);
33 } 33 }
34 final @nonnull EventTarget target; 34 final EventTarget target;
35 35
36 bool _ready = true; // last event, we were finished 36 bool _ready = true; // last event, we were finished
37 bool get ready => _ready; 37 bool get ready => _ready;
38 bool _active = false; // we have not yet been canceled since we last started l istening to a pointer 38 bool _active = false; // we have not yet been canceled since we last started l istening to a pointer
39 bool get active => _active; 39 bool get active => _active;
40 bool _chosen = false; // we're the only possible gesture at this point 40 bool _chosen = false; // we're the only possible gesture at this point
41 bool get chosen => _chosen; 41 bool get chosen => _chosen;
42 42
43 // (!ready && !active) means we're discarding events until the user 43 // (!ready && !active) means we're discarding events until the user
44 // gets to a state where a new gesture can begin 44 // gets to a state where a new gesture can begin
45 45
46 // (active && !chosen) means we're collecting events until no other 46 // (active && !chosen) means we're collecting events until no other
47 // gesture is valid, or until we take command 47 // gesture is valid, or until we take command
48 48
49 @nonnull GestureState processEvent(@nonnull PointerEvent event); 49 GestureState processEvent(PointerEvent event);
50 50
51 List<@nonnull BufferedEvent> _eventBuffer; 51 List<BufferedEvent> _eventBuffer;
52 52
53 void choose() { 53 void choose() {
54 // called by GestureManager 54 // called by GestureManager
55 // if you override this, make sure to call superclass choose() first 55 // if you override this, make sure to call superclass choose() first
56 assert(_active == true); 56 assert(_active == true);
57 assert(_chosen == false); 57 assert(_chosen == false);
58 _chosen = true; 58 _chosen = true;
59 // if there are any buffered events, dispatch them on this 59 // if there are any buffered events, dispatch them on this
60 if ((_eventBuffer != null) && (_eventBuffer.length > 0)) { 60 if ((_eventBuffer != null) && (_eventBuffer.length > 0)) {
61 // we make a copy of the event buffer first so that the array isn't mutate d out from under us 61 // we make a copy of the event buffer first so that the array isn't mutate d out from under us
62 // while we are doing this 62 // while we are doing this
63 var events = _eventBuffer; 63 var events = _eventBuffer;
64 _eventBuffer = null; 64 _eventBuffer = null;
65 for (var item in events) 65 for (var item in events)
66 dispatchEvent(item.event); 66 dispatchEvent(item.event);
67 } 67 }
68 } 68 }
69 69
70 void cancel() { 70 void cancel() {
71 // called by GestureManager 71 // called by GestureManager
72 // if you override this, make sure to call superclass cancel() last 72 // if you override this, make sure to call superclass cancel() last
73 _active = false; 73 _active = false;
74 _chosen = false; 74 _chosen = false;
75 _eventBuffer = null; 75 _eventBuffer = null;
76 } 76 }
77 77
78 // for use by subclasses only 78 // for use by subclasses only
79 void sendEvent(@nonnull GestureEvent event, 79 void sendEvent(GestureEvent event,
80 { int coallesceGroup, // when queuing events, only the last eve nt with each group is kept 80 { int coallesceGroup, // when queuing events, only the last eve nt with each group is kept
81 @nonnull bool prechoose: false // if true, event should just be sent right away, not queued 81 bool prechoose: false // if true, event should just be sent r ight away, not queued
82 }) { 82 }) {
83 assert(_active == true); 83 assert(_active == true);
84 assert(coallesceGroup == null || prechoose == false); 84 assert(coallesceGroup == null || prechoose == false);
85 event._gesture = this; 85 event._gesture = this;
86 if (_chosen || prechoose) { 86 if (_chosen || prechoose) {
87 dispatchEvent(event); 87 dispatchEvent(event);
88 } else { 88 } else {
89 if (_eventBuffer == null) 89 if (_eventBuffer == null)
90 _eventBuffer = new List<BufferedEvent>(); 90 _eventBuffer = new List<BufferedEvent>();
91 if (coallesceGroup != null) 91 if (coallesceGroup != null)
92 _eventBuffer.removeWhere((candidate) => candidate.coallesceGroup == coal lesceGroup); 92 _eventBuffer.removeWhere((candidate) => candidate.coallesceGroup == coal lesceGroup);
93 _eventBuffer.add(new BufferedEvent(event, coallesceGroup)); 93 _eventBuffer.add(new BufferedEvent(event, coallesceGroup));
94 } 94 }
95 } 95 }
96 96
97 void _handler(@nonnull Event event) { 97 void _handler(Event event) {
98 bool wasActive = _active; 98 bool wasActive = _active;
99 if (_ready) { 99 if (_ready) {
100 // reset the state to start a new gesture 100 // reset the state to start a new gesture
101 if (_active) 101 if (_active)
102 module.application.gestureManager.cancelGesture(this); 102 module.application.gestureManager.cancelGesture(this);
103 _active = true; 103 _active = true;
104 _ready = false; 104 _ready = false;
105 } 105 }
106 GestureState returnValue = processEvent(event); 106 GestureState returnValue = processEvent(event);
107 if (returnValue.capture) { 107 if (returnValue.capture) {
(...skipping 10 matching lines...) Expand all
118 } else if (active == true) { 118 } else if (active == true) {
119 if (wasActive == false || event is PointerDownEvent) 119 if (wasActive == false || event is PointerDownEvent)
120 module.application.addGesture(event, this); 120 module.application.addGesture(event, this);
121 if (returnValue.choose == true) 121 if (returnValue.choose == true)
122 module.application.chooseGesture(this); 122 module.application.chooseGesture(this);
123 } 123 }
124 _ready = returnValue.finished; 124 _ready = returnValue.finished;
125 } 125 }
126 } 126 }
127 127
128 /*
129 ``` 128 ```
130 Subclasses should override ``processEvent()``: 129 Subclasses should override ``processEvent()``:
131 - as the events are received, they get examined to see if they 130 - as the events are received, they get examined to see if they
132 fit the pattern for the gesture; if they do, then return an 131 fit the pattern for the gesture; if they do, then return an
133 object with valid=true; if more events for this gesture could 132 object with valid=true; if more events for this gesture could
134 still come in, return finished=false. 133 still come in, return finished=false.
135 - if you returned valid=false finished=false, then the next call 134 - if you returned valid=false finished=false, then the next call
136 to this must not return valid=true 135 to this must not return valid=true
137 - doing anything with the event or target other than reading 136 - doing anything with the event or target other than reading
138 state is a contract violation 137 state is a contract violation
139 - you are allowed to call sendEvent() at any time during a 138 - you are allowed to call sendEvent() at any time during a
140 processEventInternal() call, or after a call to 139 processEventInternal() call, or after a call to
141 processEventInternal(), assuming that the last such call returned 140 processEventInternal(), assuming that the last such call returned
142 valid=true, until the next call to processEventInternal() or 141 valid=true, until the next call to processEventInternal() or
143 cancel(). 142 cancel().
144 - set forceChoose=true on the return value if you are confident 143 - set forceChoose=true on the return value if you are confident
145 that this is the gesture the user meant, even if it's possible 144 that this is the gesture the user meant, even if it's possible
146 that another gesture is still claiming it's valid (e.g. a long 145 that another gesture is still claiming it's valid (e.g. a long
147 press might forceChoose to override a scroll, if the user 146 press might forceChoose to override a scroll, if the user
148 hasn't moved for a while) 147 hasn't moved for a while)
149 - if you send events, you can set prechoose=true to send the 148 - if you send events, you can set prechoose=true to send the
150 event even before the gesture has been chosen 149 event even before the gesture has been chosen
151 - if you send prechoose events, make sure to send corresponding 150 - if you send prechoose events, make sure to send corresponding
152 "cancel" events if cancel() is called 151 "cancel" events if cancel() is called
153 152
154 ```dart 153 ```dart
155 */
156 154
157 class PointerState { 155 class PointerState {
158 PointerState({this.gestures, this.chosen}) { 156 PointerState({this.gestures, this.chosen}) {
159 if (gestures == null) 157 if (gestures == null)
160 gestures = new List<Gesture>(); 158 gestures = new List<Gesture>();
161 } 159 }
162 factory PointerState.clone(PointerState source) { 160 factory PointerState.clone(PointerState source) {
163 return new PointerState(gestures: source.gestures, chosen: source.chosen); 161 return new PointerState(gestures: source.gestures, chosen: source.chosen);
164 } 162 }
165 @nonnull List<@nonnull Gesture> gestures; 163 List<Gesture> gestures;
166 @nonnull bool chosen = false; 164 bool chosen = false;
167 } 165 }
168 166
169 class GestureManager { 167 class GestureManager {
170 GestureManager(this.target) { 168 GestureManager(this.target) {
171 target.events.where((event) => event is PointerDownEvent).listen(_handler); 169 target.events.where((event) => event is PointerDownEvent).listen(_handler);
172 } 170 }
173 final @nonnull EventTarget target; // usually the ApplicationRoot object 171 final EventTarget target; // usually the ApplicationRoot object
174 172
175 Map<@nonnull int, @nonnull PointerState> _pointers = new SplayTreeMap<int, Poi nterState>(); 173 Map<int, PointerState> _pointers = new SplayTreeMap<int, PointerState>();
176 174
177 void addGesture(@nonnull PointerEvent event, @nonnull Gesture gesture) { 175 void addGesture(PointerEvent event, Gesture gesture) {
178 assert(gesture.active); 176 assert(gesture.active);
179 var pointer = event.pointer; 177 var pointer = event.pointer;
180 if (_pointers.containsKey(pointer)) { 178 if (_pointers.containsKey(pointer)) {
181 assert(!_pointers[pointer].gestures.contains(gesture)); 179 assert(!_pointers[pointer].gestures.contains(gesture));
182 if (_pointers[pointer].chosen) 180 if (_pointers[pointer].chosen)
183 cancelGesture(gesture); 181 cancelGesture(gesture);
184 else 182 else
185 _pointers[pointer].gestures.add(gesture); 183 _pointers[pointer].gestures.add(gesture);
186 } else { 184 } else {
187 PointerState pointerState = new PointerState(); 185 PointerState pointerState = new PointerState();
188 pointerState.gestures.add(gesture); 186 pointerState.gestures.add(gesture);
189 _pointers[pointer] = pointerState; 187 _pointers[pointer] = pointerState;
190 } 188 }
191 } 189 }
192 190
193 void cancelGesture(@nonnull Gesture gesture) { 191 void cancelGesture(Gesture gesture) {
194 _pointers.forEach((index, pointerState) => pointerState.gestures.remove(gest ure)); 192 _pointers.forEach((index, pointerState) => pointerState.gestures.remove(gest ure));
195 gesture.cancel(); 193 gesture.cancel();
196 // get a static copy of the _pointers keys, so we can remove them safely 194 // get a static copy of the _pointers keys, so we can remove them safely
197 var activePointers = new List<int>.from(_pointers.keys); 195 var activePointers = new List<int>.from(_pointers.keys);
198 // now walk our lists, removing pointers that are obsolete, and choosing 196 // now walk our lists, removing pointers that are obsolete, and choosing
199 // gestures from pointers that have only one outstanding gesture 197 // gestures from pointers that have only one outstanding gesture
200 for (var pointer in activePointers) { 198 for (var pointer in activePointers) {
201 var pointerState = _pointers[pointer]; 199 var pointerState = _pointers[pointer];
202 if (pointerState.gestures.length == 0) { 200 if (pointerState.gestures.length == 0) {
203 _pointers.remove(pointer); 201 _pointers.remove(pointer);
204 } else { 202 } else {
205 if (pointerState.gestures.length == 1 && pointerState.chosen) { 203 if (pointerState.gestures.length == 1 && pointerState.chosen) {
206 pointerState.chosen = true; 204 pointerState.chosen = true;
207 pointerState.gestures[0].choose(); 205 pointerState.gestures[0].choose();
208 } 206 }
209 } 207 }
210 } 208 }
211 } 209 }
212 210
213 void chooseGesture(@nonnull Gesture gesture) { 211 void chooseGesture(Gesture gesture) {
214 if (!gesture.active) 212 if (!gesture.active)
215 // this could happen e.g. if two gestures simultaneously add 213 // this could happen e.g. if two gestures simultaneously add
216 // themselves and chose themselves for the same PointerDownEvent 214 // themselves and chose themselves for the same PointerDownEvent
217 return; 215 return;
218 @nonnull List<@nonnull Gesture> losers = new List<@nonnull Gesture>(); 216 List<Gesture> losers = new List<Gesture>();
219 _pointers.values 217 _pointers.values
220 .where((pointerState) => pointerState.gestures.contains(gesture)) 218 .where((pointerState) => pointerState.gestures.contains(gesture))
221 .forEach((pointerState) { 219 .forEach((pointerState) {
222 losers.addAll(pointerState.gestures.where((candidateLoser) => can didateLoser != gesture)); 220 losers.addAll(pointerState.gestures.where((candidateLoser) => can didateLoser != gesture));
223 pointerState.gestures.clear(); 221 pointerState.gestures.clear();
224 pointerState.gestures.add(gesture); 222 pointerState.gestures.add(gesture);
225 pointerState.chosen = true; 223 pointerState.chosen = true;
226 }); 224 });
227 assert(losers.every((loser) => loser.active)); 225 assert(losers.every((loser) => loser.active));
228 losers.forEach((loser) { 226 losers.forEach((loser) {
229 // we check loser.active because losers could contain duplicates 227 // we check loser.active because losers could contain duplicates
230 // and we should only cancel each gesture once 228 // and we should only cancel each gesture once
231 if (loser.active) 229 if (loser.active)
232 loser.cancel(); 230 loser.cancel();
233 assert(!loser.active); 231 assert(!loser.active);
234 }); 232 });
235 gesture.choose(); 233 gesture.choose();
236 } 234 }
237 235
238 @nonnull PointerState getActiveGestures(@nonnull int pointer) { 236 PointerState getActiveGestures(int pointer) {
239 if (_pointers.containsKey(pointer) && _pointers[pointer].gestures.length > 0 ) 237 if (_pointers.containsKey(pointer) && _pointers[pointer].gestures.length > 0 )
240 return new PointerState.clone(_pointers[pointer]); 238 return new PointerState.clone(_pointers[pointer]);
241 return new PointerState(); 239 return new PointerState();
242 } 240 }
243 241
244 void _handler(@nonnull PointerDownEvent event) { 242 void _handler(PointerDownEvent event) {
245 var pointer = event.pointer; 243 var pointer = event.pointer;
246 if (_pointers.containsKey(pointer)) { 244 if (_pointers.containsKey(pointer)) {
247 var pointerState = _pointers[pointer]; 245 var pointerState = _pointers[pointer];
248 if ((!pointerState.chosen) && (pointerState.gestures.length == 1)) { 246 if ((!pointerState.chosen) && (pointerState.gestures.length == 1)) {
249 pointerState.chosen = true; 247 pointerState.chosen = true;
250 pointerState.gestures[0].choose(); 248 pointerState.gestures[0].choose();
251 } 249 }
252 } 250 }
253 } 251 }
254 252
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 // fling-end: cancel(), or after fling or fling-cancel (prechoose) 419 // fling-end: cancel(), or after fling or fling-cancel (prechoose)
422 } 420 }
423 421
424 class FlingLeftGesture : FlingGesture { } 422 class FlingLeftGesture : FlingGesture { }
425 class FlingRightGesture : FlingGesture { } 423 class FlingRightGesture : FlingGesture { }
426 class FlingUpGesture : FlingGesture { } 424 class FlingUpGesture : FlingGesture { }
427 class FlingDownGesture : FlingGesture { } 425 class FlingDownGesture : FlingGesture { }
428 426
429 </script> 427 </script>
430 ``` 428 ```
OLDNEW
« no previous file with comments | « no previous file | sky/specs/pointer.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698