// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:sky' as sky; import 'package:sky/gestures.dart'; import 'package:sky/src/rendering/sky_binding.dart'; import 'package:sky/src/widgets/framework.dart'; class GestureDetector extends StatefulComponent { GestureDetector({ Key key, this.child, this.onTap, this.onShowPress, this.onLongPress, this.onVerticalDragStart, this.onVerticalDragUpdate, this.onVerticalDragEnd, this.onHorizontalDragStart, this.onHorizontalDragUpdate, this.onHorizontalDragEnd, this.onPanStart, this.onPanUpdate, this.onPanEnd, this.onScaleStart, this.onScaleUpdate, this.onScaleEnd }) : super(key: key); Widget child; GestureTapListener onTap; GestureShowPressListener onShowPress; GestureLongPressListener onLongPress; GestureDragStartCallback onVerticalDragStart; GestureDragUpdateCallback onVerticalDragUpdate; GestureDragEndCallback onVerticalDragEnd; GestureDragStartCallback onHorizontalDragStart; GestureDragUpdateCallback onHorizontalDragUpdate; GestureDragEndCallback onHorizontalDragEnd; GesturePanStartCallback onPanStart; GesturePanUpdateCallback onPanUpdate; GesturePanEndCallback onPanEnd; GestureScaleStartCallback onScaleStart; GestureScaleUpdateCallback onScaleUpdate; GestureScaleEndCallback onScaleEnd; void syncConstructorArguments(GestureDetector source) { child = source.child; onTap = source.onTap; onShowPress = source.onShowPress; onLongPress = source.onLongPress; onVerticalDragStart = source.onVerticalDragStart; onVerticalDragUpdate = source.onVerticalDragUpdate; onVerticalDragEnd = source.onVerticalDragEnd; onHorizontalDragStart = source.onHorizontalDragStart; onHorizontalDragUpdate = source.onHorizontalDragUpdate; onHorizontalDragEnd = source.onHorizontalDragEnd; onPanStart = source.onPanStart; onPanUpdate = source.onPanUpdate; onPanEnd = source.onPanEnd; onScaleStart = source.onScaleStart; onScaleUpdate = source.onScaleUpdate; onScaleEnd = source.onScaleEnd; _syncGestureListeners(); } final PointerRouter _router = SkyBinding.instance.pointerRouter; TapGestureRecognizer _tap; TapGestureRecognizer _ensureTap() { if (_tap == null) _tap = new TapGestureRecognizer(router: _router); return _tap; } ShowPressGestureRecognizer _showPress; ShowPressGestureRecognizer _ensureShowPress() { if (_showPress == null) _showPress = new ShowPressGestureRecognizer(router: _router); return _showPress; } LongPressGestureRecognizer _longPress; LongPressGestureRecognizer _ensureLongPress() { if (_longPress == null) _longPress = new LongPressGestureRecognizer(router: _router); return _longPress; } VerticalDragGestureRecognizer _verticalDrag; VerticalDragGestureRecognizer _ensureVerticalDrag() { if (_verticalDrag == null) _verticalDrag = new VerticalDragGestureRecognizer(router: _router); return _verticalDrag; } HorizontalDragGestureRecognizer _horizontalDrag; HorizontalDragGestureRecognizer _ensureHorizontalDrag() { if (_horizontalDrag == null) _horizontalDrag = new HorizontalDragGestureRecognizer(router: _router); return _horizontalDrag; } PanGestureRecognizer _pan; PanGestureRecognizer _ensurePan() { assert(_scale == null); // Scale is a superset of pan; just use scale if (_pan == null) _pan = new PanGestureRecognizer(router: _router); return _pan; } ScaleGestureRecognizer _scale; ScaleGestureRecognizer _ensureScale() { assert(_pan == null); // Scale is a superset of pan; just use scale if (_scale == null) _scale = new ScaleGestureRecognizer(router: _router); return _scale; } void didMount() { super.didMount(); _syncGestureListeners(); } void didUnmount() { super.didUnmount(); _tap = _ensureDisposed(_tap); _showPress = _ensureDisposed(_showPress); _longPress = _ensureDisposed(_longPress); _verticalDrag = _ensureDisposed(_verticalDrag); _horizontalDrag = _ensureDisposed(_horizontalDrag); _pan = _ensureDisposed(_pan); _scale = _ensureDisposed(_scale); } void _syncGestureListeners() { _syncTap(); _syncShowPress(); _syncLongPress(); _syncVerticalDrag(); _syncHorizontalDrag(); _syncPan(); _syncScale(); } void _syncTap() { if (onTap == null) _tap = _ensureDisposed(_tap); else _ensureTap().onTap = onTap; } void _syncShowPress() { if (onShowPress == null) _showPress = _ensureDisposed(_showPress); else _ensureShowPress().onShowPress = onShowPress; } void _syncLongPress() { if (onLongPress == null) _longPress = _ensureDisposed(_longPress); else _ensureLongPress().onLongPress = onLongPress; } void _syncVerticalDrag() { if (onVerticalDragStart == null && onVerticalDragUpdate == null && onVerticalDragEnd == null) { _verticalDrag = _ensureDisposed(_verticalDrag); } else { _ensureVerticalDrag() ..onStart = onVerticalDragStart ..onUpdate = onVerticalDragUpdate ..onEnd = onVerticalDragEnd; } } void _syncHorizontalDrag() { if (onHorizontalDragStart == null && onHorizontalDragUpdate == null && onHorizontalDragEnd == null) { _horizontalDrag = _ensureDisposed(_horizontalDrag); } else { _ensureHorizontalDrag() ..onStart = onHorizontalDragStart ..onUpdate = onHorizontalDragUpdate ..onEnd = onHorizontalDragEnd; } } void _syncPan() { if (onPanStart == null && onPanUpdate == null && onPanEnd == null) { _pan = _ensureDisposed(_pan); } else { _ensurePan() ..onStart = onPanStart ..onUpdate = onPanUpdate ..onEnd = onPanEnd; } } void _syncScale() { if (onScaleStart == null && onScaleUpdate == null && onScaleEnd == null) { _scale = _ensureDisposed(_pan); } else { _ensureScale() ..onStart = onScaleStart ..onUpdate = onScaleUpdate ..onEnd = onScaleEnd; } } GestureRecognizer _ensureDisposed(GestureRecognizer recognizer) { recognizer?.dispose(); return null; } EventDisposition _handlePointerDown(sky.PointerEvent event) { if (_tap != null) _tap.addPointer(event); if (_showPress != null) _showPress.addPointer(event); if (_longPress != null) _longPress.addPointer(event); if (_verticalDrag != null) _verticalDrag.addPointer(event); if (_horizontalDrag != null) _horizontalDrag.addPointer(event); if (_pan != null) _pan.addPointer(event); if (_scale != null) _scale.addPointer(event); return EventDisposition.processed; } Widget build() { return new Listener( onPointerDown: _handlePointerDown, child: child ); } }