Line data Source code
1 : import 'package:flutter/gestures.dart';
2 : import 'package:flutter/widgets.dart';
3 :
4 : import '../../../components.dart';
5 : import '../../../extensions.dart';
6 : import '../../components/mixins/draggable.dart';
7 : import '../../extensions/offset.dart';
8 : import '../../gestures/detectors.dart';
9 : import '../../gestures/events.dart';
10 : import '../game.dart';
11 :
12 8 : bool hasBasicGestureDetectors(Game game) =>
13 8 : game is TapDetector ||
14 8 : game is SecondaryTapDetector ||
15 8 : game is DoubleTapDetector ||
16 8 : game is LongPressDetector ||
17 8 : game is VerticalDragDetector ||
18 8 : game is HorizontalDragDetector ||
19 8 : game is ForcePressDetector ||
20 8 : game is PanDetector ||
21 8 : game is ScaleDetector;
22 :
23 8 : bool hasAdvancedGesturesDetectors(Game game) =>
24 8 : game is MultiTouchTapDetector ||
25 8 : game is MultiTouchDragDetector ||
26 8 : game is HasTappableComponents ||
27 7 : game is HasDraggableComponents;
28 :
29 8 : bool hasMouseDetectors(Game game) =>
30 8 : game is MouseMovementDetector ||
31 8 : game is ScrollDetector ||
32 8 : game is HasHoverableComponents;
33 :
34 0 : Widget applyBasicGesturesDetectors(Game game, Widget child) {
35 0 : return GestureDetector(
36 : key: const ObjectKey('BasicGesturesDetector'),
37 : behavior: HitTestBehavior.opaque,
38 :
39 : // Taps
40 0 : onTap: game is TapDetector ? () => game.onTap() : null,
41 0 : onTapCancel: game is TapDetector ? () => game.onTapCancel() : null,
42 0 : onTapDown: game is TapDetector
43 0 : ? (TapDownDetails d) => game.onTapDown(TapDownInfo.fromDetails(game, d))
44 : : null,
45 0 : onTapUp: game is TapDetector
46 0 : ? (TapUpDetails d) => game.onTapUp(TapUpInfo.fromDetails(game, d))
47 : : null,
48 :
49 : // Secondary taps
50 0 : onSecondaryTapDown: game is SecondaryTapDetector
51 0 : ? (TapDownDetails d) =>
52 0 : game.onSecondaryTapDown(TapDownInfo.fromDetails(game, d))
53 : : null,
54 0 : onSecondaryTapUp: game is SecondaryTapDetector
55 0 : ? (TapUpDetails d) =>
56 0 : game.onSecondaryTapUp(TapUpInfo.fromDetails(game, d))
57 : : null,
58 : onSecondaryTapCancel:
59 0 : game is SecondaryTapDetector ? () => game.onSecondaryTapCancel() : null,
60 :
61 : // Double tap
62 0 : onDoubleTap: game is DoubleTapDetector ? () => game.onDoubleTap() : null,
63 :
64 : // Long presses
65 0 : onLongPress: game is LongPressDetector ? () => game.onLongPress() : null,
66 0 : onLongPressStart: game is LongPressDetector
67 0 : ? (LongPressStartDetails d) =>
68 0 : game.onLongPressStart(LongPressStartInfo.fromDetails(game, d))
69 : : null,
70 0 : onLongPressMoveUpdate: game is LongPressDetector
71 0 : ? (LongPressMoveUpdateDetails d) => game
72 0 : .onLongPressMoveUpdate(LongPressMoveUpdateInfo.fromDetails(game, d))
73 : : null,
74 : onLongPressUp:
75 0 : game is LongPressDetector ? () => game.onLongPressUp() : null,
76 0 : onLongPressEnd: game is LongPressDetector
77 0 : ? (LongPressEndDetails d) =>
78 0 : game.onLongPressEnd(LongPressEndInfo.fromDetails(game, d))
79 : : null,
80 :
81 : // Vertical drag
82 0 : onVerticalDragDown: game is VerticalDragDetector
83 0 : ? (DragDownDetails d) =>
84 0 : game.onVerticalDragDown(DragDownInfo.fromDetails(game, d))
85 : : null,
86 0 : onVerticalDragStart: game is VerticalDragDetector
87 0 : ? (DragStartDetails d) =>
88 0 : game.onVerticalDragStart(DragStartInfo.fromDetails(game, d))
89 : : null,
90 0 : onVerticalDragUpdate: game is VerticalDragDetector
91 0 : ? (DragUpdateDetails d) =>
92 0 : game.onVerticalDragUpdate(DragUpdateInfo.fromDetails(game, d))
93 : : null,
94 0 : onVerticalDragEnd: game is VerticalDragDetector
95 0 : ? (DragEndDetails d) =>
96 0 : game.onVerticalDragEnd(DragEndInfo.fromDetails(game, d))
97 : : null,
98 : onVerticalDragCancel:
99 0 : game is VerticalDragDetector ? () => game.onVerticalDragCancel() : null,
100 :
101 : // Horizontal drag
102 0 : onHorizontalDragDown: game is HorizontalDragDetector
103 0 : ? (DragDownDetails d) =>
104 0 : game.onHorizontalDragDown(DragDownInfo.fromDetails(game, d))
105 : : null,
106 0 : onHorizontalDragStart: game is HorizontalDragDetector
107 0 : ? (DragStartDetails d) =>
108 0 : game.onHorizontalDragStart(DragStartInfo.fromDetails(game, d))
109 : : null,
110 0 : onHorizontalDragUpdate: game is HorizontalDragDetector
111 0 : ? (DragUpdateDetails d) =>
112 0 : game.onHorizontalDragUpdate(DragUpdateInfo.fromDetails(game, d))
113 : : null,
114 0 : onHorizontalDragEnd: game is HorizontalDragDetector
115 0 : ? (DragEndDetails d) =>
116 0 : game.onHorizontalDragEnd(DragEndInfo.fromDetails(game, d))
117 : : null,
118 0 : onHorizontalDragCancel: game is HorizontalDragDetector
119 0 : ? () => game.onHorizontalDragCancel()
120 : : null,
121 :
122 : // Force presses
123 0 : onForcePressStart: game is ForcePressDetector
124 0 : ? (ForcePressDetails d) =>
125 0 : game.onForcePressStart(ForcePressInfo.fromDetails(game, d))
126 : : null,
127 0 : onForcePressPeak: game is ForcePressDetector
128 0 : ? (ForcePressDetails d) =>
129 0 : game.onForcePressPeak(ForcePressInfo.fromDetails(game, d))
130 : : null,
131 0 : onForcePressUpdate: game is ForcePressDetector
132 0 : ? (ForcePressDetails d) =>
133 0 : game.onForcePressUpdate(ForcePressInfo.fromDetails(game, d))
134 : : null,
135 0 : onForcePressEnd: game is ForcePressDetector
136 0 : ? (ForcePressDetails d) =>
137 0 : game.onForcePressEnd(ForcePressInfo.fromDetails(game, d))
138 : : null,
139 :
140 : // Pan
141 0 : onPanDown: game is PanDetector
142 0 : ? (DragDownDetails d) =>
143 0 : game.onPanDown(DragDownInfo.fromDetails(game, d))
144 : : null,
145 0 : onPanStart: game is PanDetector
146 0 : ? (DragStartDetails d) =>
147 0 : game.onPanStart(DragStartInfo.fromDetails(game, d))
148 : : null,
149 0 : onPanUpdate: game is PanDetector
150 0 : ? (DragUpdateDetails d) =>
151 0 : game.onPanUpdate(DragUpdateInfo.fromDetails(game, d))
152 : : null,
153 0 : onPanEnd: game is PanDetector
154 0 : ? (DragEndDetails d) => game.onPanEnd(DragEndInfo.fromDetails(game, d))
155 : : null,
156 0 : onPanCancel: game is PanDetector ? () => game.onPanCancel() : null,
157 :
158 : // Scales
159 0 : onScaleStart: game is ScaleDetector
160 0 : ? (ScaleStartDetails d) =>
161 0 : game.onScaleStart(ScaleStartInfo.fromDetails(game, d))
162 : : null,
163 0 : onScaleUpdate: game is ScaleDetector
164 0 : ? (ScaleUpdateDetails d) =>
165 0 : game.onScaleUpdate(ScaleUpdateInfo.fromDetails(game, d))
166 : : null,
167 0 : onScaleEnd: game is ScaleDetector
168 0 : ? (ScaleEndDetails d) =>
169 0 : game.onScaleEnd(ScaleEndInfo.fromDetails(game, d))
170 : : null,
171 :
172 : child: child,
173 : );
174 : }
175 :
176 1 : Widget applyAdvancedGesturesDetectors(Game game, Widget child) {
177 1 : final gestures = <Type, GestureRecognizerFactory>{};
178 : var lastGeneratedDragId = 0;
179 :
180 1 : void addAndConfigureRecognizer<T extends GestureRecognizer>(
181 : T Function() ts,
182 : void Function(T) bindHandlers,
183 : ) {
184 2 : gestures[T] = GestureRecognizerFactoryWithHandlers<T>(
185 : ts,
186 : bindHandlers,
187 : );
188 : }
189 :
190 0 : void addTapRecognizer(void Function(MultiTapGestureRecognizer) config) {
191 0 : addAndConfigureRecognizer(
192 0 : () => MultiTapGestureRecognizer(),
193 : config,
194 : );
195 : }
196 :
197 0 : void addDragRecognizer(Game game, Drag Function(int, DragStartInfo) config) {
198 0 : addAndConfigureRecognizer(
199 0 : () => ImmediateMultiDragGestureRecognizer(),
200 0 : (ImmediateMultiDragGestureRecognizer instance) {
201 0 : instance.onStart = (Offset o) {
202 0 : final pointerId = lastGeneratedDragId++;
203 :
204 : final global = o;
205 : final local = game
206 0 : .convertGlobalToLocalCoordinate(
207 0 : global.toVector2(),
208 : )
209 0 : .toOffset();
210 :
211 0 : final details = DragStartDetails(
212 : localPosition: local,
213 : globalPosition: global,
214 : );
215 0 : return config(
216 : pointerId,
217 0 : DragStartInfo.fromDetails(game, details),
218 : );
219 : };
220 : },
221 : );
222 : }
223 :
224 1 : if (game is MultiTouchTapDetector) {
225 0 : addTapRecognizer((MultiTapGestureRecognizer instance) {
226 0 : instance.onTapDown =
227 0 : (i, d) => game.onTapDown(i, TapDownInfo.fromDetails(game, d));
228 0 : instance.onTapUp =
229 0 : (i, d) => game.onTapUp(i, TapUpInfo.fromDetails(game, d));
230 0 : instance.onTapCancel = game.onTapCancel;
231 0 : instance.onTap = game.onTap;
232 : });
233 1 : } else if (game is HasTappableComponents) {
234 1 : addAndConfigureRecognizer(
235 0 : () => MultiTapGestureRecognizer(),
236 0 : (MultiTapGestureRecognizer instance) {
237 0 : instance.onTapDown =
238 0 : (i, d) => game.onTapDown(i, TapDownInfo.fromDetails(game, d));
239 0 : instance.onTapUp =
240 0 : (i, d) => game.onTapUp(i, TapUpInfo.fromDetails(game, d));
241 0 : instance.onTapCancel = (i) => game.onTapCancel(i);
242 : },
243 : );
244 : }
245 :
246 1 : if (game is MultiTouchDragDetector) {
247 0 : addDragRecognizer(game, (int pointerId, DragStartInfo info) {
248 0 : game.onDragStart(pointerId, info);
249 0 : return _DragEvent(game)
250 0 : ..onUpdate = ((details) => game.onDragUpdate(pointerId, details))
251 0 : ..onEnd = ((details) => game.onDragEnd(pointerId, details))
252 0 : ..onCancel = (() => game.onDragCancel(pointerId));
253 : });
254 1 : } else if (game is HasDraggableComponents) {
255 0 : addDragRecognizer(game, (int pointerId, DragStartInfo position) {
256 0 : game.onDragStart(pointerId, position);
257 0 : return _DragEvent(game)
258 0 : ..onUpdate = ((details) => game.onDragUpdate(pointerId, details))
259 0 : ..onEnd = ((details) => game.onDragEnd(pointerId, details))
260 0 : ..onCancel = (() => game.onDragCancel(pointerId));
261 : });
262 : }
263 :
264 1 : return RawGestureDetector(
265 : gestures: gestures,
266 : behavior: HitTestBehavior.opaque,
267 : child: child,
268 : );
269 : }
270 :
271 0 : Widget applyMouseDetectors(Game game, Widget child) {
272 0 : final mouseMoveFn = game is MouseMovementDetector
273 0 : ? game.onMouseMove
274 0 : : (game is HasHoverableComponents ? game.onMouseMove : null);
275 0 : return Listener(
276 0 : child: MouseRegion(
277 : child: child,
278 0 : onHover: (e) => mouseMoveFn?.call(PointerHoverInfo.fromDetails(game, e)),
279 : ),
280 0 : onPointerSignal: (event) =>
281 0 : game is ScrollDetector && event is PointerScrollEvent
282 0 : ? game.onScroll(PointerScrollInfo.fromDetails(game, event))
283 : : null,
284 : );
285 : }
286 :
287 : class _DragEvent extends Drag {
288 : final Game gameRef;
289 : void Function(DragUpdateInfo)? onUpdate;
290 : VoidCallback? onCancel;
291 : void Function(DragEndInfo)? onEnd;
292 :
293 0 : _DragEvent(this.gameRef);
294 :
295 0 : @override
296 : void update(DragUpdateDetails details) {
297 0 : final event = DragUpdateInfo.fromDetails(gameRef, details);
298 0 : onUpdate?.call(event);
299 : }
300 :
301 0 : @override
302 : void cancel() {
303 0 : onCancel?.call();
304 : }
305 :
306 0 : @override
307 : void end(DragEndDetails details) {
308 0 : final event = DragEndInfo.fromDetails(gameRef, details);
309 0 : onEnd?.call(event);
310 : }
311 : }
|