diff --git a/packages/flutter/lib/src/gestures/events.dart b/packages/flutter/lib/src/gestures/events.dart index 031017b1f2..722b9984a9 100644 --- a/packages/flutter/lib/src/gestures/events.dart +++ b/packages/flutter/lib/src/gestures/events.dart @@ -2,25 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui; - /// Base class for input events. class InputEvent { const InputEvent({ this.type, this.timeStamp: 0.0 }); - factory InputEvent.fromUiEvent(ui.Event event) { - if (event is ui.PointerEvent) - return new PointerInputEvent.fromUiEvent(event); - - // Default event - return new InputEvent( - type: event.type, - timeStamp: event.timeStamp - ); - } - final String type; + // TODO: Should timeStamp be a DateTime object instead of double? + // Some client code (e.g. drag.dart) does math on the time stamp. final double timeStamp; } @@ -55,53 +44,6 @@ class PointerInputEvent extends InputEvent { this.tilt }) : super(type: type, timeStamp: timeStamp); - factory PointerInputEvent.fromUiEvent(ui.PointerEvent event) { - PointerInputEvent result = new PointerInputEvent( - type: event.type, - timeStamp: event.timeStamp, - pointer: _getPointerValue(event.type, event.pointer), - kind: event.kind, - x: event.x, - y: event.y, - dx: event.dx, - dy: event.dy, - buttons: event.buttons, - down: event.down, - primary: event.primary, - obscured: event.obscured, - pressure: event.pressure, - pressureMin: event.pressureMin, - pressureMax: event.pressureMax, - distance: event.distance, - distanceMin: event.distanceMin, - distanceMax: event.distanceMax, - radiusMajor: event.radiusMajor, - radiusMinor: event.radiusMinor, - radiusMin: event.radiusMin, - radiusMax: event.radiusMax, - orientation: event.orientation, - tilt: event.tilt - ); - return result; - } - - // Map actual input pointer value to a unique value - // Since events are serialized we can just use a counter - static Map _pointerMap = new Map(); - static int _pointerCount = 0; - - static int _getPointerValue(String eventType, int pointer) { - int result; - if (eventType == 'pointerdown') { - result = pointer; - _pointerMap[pointer] = _pointerCount; - _pointerCount++; - } else { - result = _pointerMap[pointer]; - } - return result; - } - final int pointer; final String kind; final double x; diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 99685d3d34..3484b40469 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -23,12 +23,6 @@ int _hammingWeight(int value) { return weight; } -class _PointerState { - _PointerState({ this.result, this.lastPosition }); - HitTestResult result; - Point lastPosition; -} - typedef void EventListener(InputEvent event); /// A hit test entry used by [FlutterBinding] @@ -39,6 +33,93 @@ class BindingHitTestEntry extends HitTestEntry { final HitTestResult result; } +/// State used in converting ui.Event to InputEvent +class _PointerState { + _PointerState({ this.pointer, this.lastPosition }); + int pointer; + Point lastPosition; +} + +class _UiEventConverter { + static InputEvent convert(ui.Event event) { + if (event is ui.PointerEvent) + return convertPointerEvent(event); + + // Default event + return new InputEvent( + type: event.type, + timeStamp: event.timeStamp + ); + } + + // Map actual input pointer value to a unique value + // Since events are serialized we can just use a counter + static Map _stateForPointer = new Map(); + static int _pointerCount = 0; + + static PointerInputEvent convertPointerEvent(ui.PointerEvent event) { + Point position = new Point(event.x, event.y); + + _PointerState state = _stateForPointer[event.pointer]; + double dx, dy; + switch (event.type) { + case 'pointerdown': + if (state == null) { + state = new _PointerState(lastPosition: position); + _stateForPointer[event.pointer] = state; + } + state.pointer = _pointerCount; + _pointerCount++; + break; + case 'pointermove': + // state == null means the pointer is hovering + if (state != null) { + dx = position.x - state.lastPosition.x; + dy = position.y - state.lastPosition.y; + state.lastPosition = position; + } + break; + case 'pointerup': + case 'pointercancel': + // state == null indicates spurious events + if (state != null) { + // Only remove the pointer state when the last button has been released. + if (_hammingWeight(event.buttons) <= 1) + _stateForPointer.remove(event.pointer); + } + break; + } + + return new PointerInputEvent( + type: event.type, + timeStamp: event.timeStamp, + pointer: state.pointer, + kind: event.kind, + x: event.x, + y: event.y, + dx: dx, + dy: dy, + buttons: event.buttons, + down: event.down, + primary: event.primary, + obscured: event.obscured, + pressure: event.pressure, + pressureMin: event.pressureMin, + pressureMax: event.pressureMax, + distance: event.distance, + distanceMin: event.distanceMin, + distanceMax: event.distanceMax, + radiusMajor: event.radiusMajor, + radiusMinor: event.radiusMinor, + radiusMin: event.radiusMin, + radiusMax: event.radiusMax, + orientation: event.orientation, + tilt: event.tilt + ); + } + +} + /// The glue between the render tree and the Flutter engine class FlutterBinding extends HitTestTarget { @@ -95,7 +176,7 @@ class FlutterBinding extends HitTestTarget { bool removeEventListener(EventListener listener) => _eventListeners.remove(listener); void _handleEvent(ui.Event event) { - InputEvent ourEvent = new InputEvent.fromUiEvent(event); + InputEvent ourEvent = _UiEventConverter.convert(event); if (ourEvent is PointerInputEvent) { _handlePointerInputEvent(ourEvent); } else { @@ -110,41 +191,36 @@ class FlutterBinding extends HitTestTarget { /// State for all pointers which are currently down. /// We do not track the state of hovering pointers because we need /// to hit-test them on each movement. - Map _stateForPointer = new Map(); + Map _resultForPointer = new Map(); void _handlePointerInputEvent(PointerInputEvent event) { - Point position = new Point(event.x, event.y); - - _PointerState state = _stateForPointer[event.pointer]; + HitTestResult result = _resultForPointer[event.pointer]; switch (event.type) { case 'pointerdown': - if (state == null) { - state = new _PointerState(result: hitTest(position), lastPosition: position); - _stateForPointer[event.pointer] = state; + if (result == null) { + result = hitTest(new Point(event.x, event.y)); + _resultForPointer[event.pointer] = result; } break; case 'pointermove': - if (state == null) { + if (result == null) { // The pointer is hovering, ignore it for now since we don't // know what to do with it yet. return; } - event.dx = position.x - state.lastPosition.x; - event.dy = position.y - state.lastPosition.y; - state.lastPosition = position; break; case 'pointerup': case 'pointercancel': - if (state == null) { + if (result == null) { // This seems to be a spurious event. Ignore it. return; } - // Only remove the pointer state when the last button has been released. + // Only remove the hit test result when the last button has been released. if (_hammingWeight(event.buttons) <= 1) - _stateForPointer.remove(event.pointer); + _resultForPointer.remove(event.pointer); break; } - dispatchEvent(event, state.result); + dispatchEvent(event, result); } /// Determine which [HitTestTarget] objects are located at a given position