Refactor to move conversion into the binding class
This commit is contained in:
parent
0284321483
commit
52c1fe5105
@ -2,25 +2,14 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:ui' as ui;
|
|
||||||
|
|
||||||
/// Base class for input events.
|
/// Base class for input events.
|
||||||
class InputEvent {
|
class InputEvent {
|
||||||
|
|
||||||
const InputEvent({ this.type, this.timeStamp: 0.0 });
|
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;
|
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;
|
final double timeStamp;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -55,53 +44,6 @@ class PointerInputEvent extends InputEvent {
|
|||||||
this.tilt
|
this.tilt
|
||||||
}) : super(type: type, timeStamp: timeStamp);
|
}) : 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<int, int> _pointerMap = new Map<int, int>();
|
|
||||||
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 int pointer;
|
||||||
final String kind;
|
final String kind;
|
||||||
final double x;
|
final double x;
|
||||||
|
@ -23,12 +23,6 @@ int _hammingWeight(int value) {
|
|||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PointerState {
|
|
||||||
_PointerState({ this.result, this.lastPosition });
|
|
||||||
HitTestResult result;
|
|
||||||
Point lastPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef void EventListener(InputEvent event);
|
typedef void EventListener(InputEvent event);
|
||||||
|
|
||||||
/// A hit test entry used by [FlutterBinding]
|
/// A hit test entry used by [FlutterBinding]
|
||||||
@ -39,6 +33,93 @@ class BindingHitTestEntry extends HitTestEntry {
|
|||||||
final HitTestResult result;
|
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<int, _PointerState> _stateForPointer = new Map<int, _PointerState>();
|
||||||
|
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
|
/// The glue between the render tree and the Flutter engine
|
||||||
class FlutterBinding extends HitTestTarget {
|
class FlutterBinding extends HitTestTarget {
|
||||||
|
|
||||||
@ -95,7 +176,7 @@ class FlutterBinding extends HitTestTarget {
|
|||||||
bool removeEventListener(EventListener listener) => _eventListeners.remove(listener);
|
bool removeEventListener(EventListener listener) => _eventListeners.remove(listener);
|
||||||
|
|
||||||
void _handleEvent(ui.Event event) {
|
void _handleEvent(ui.Event event) {
|
||||||
InputEvent ourEvent = new InputEvent.fromUiEvent(event);
|
InputEvent ourEvent = _UiEventConverter.convert(event);
|
||||||
if (ourEvent is PointerInputEvent) {
|
if (ourEvent is PointerInputEvent) {
|
||||||
_handlePointerInputEvent(ourEvent);
|
_handlePointerInputEvent(ourEvent);
|
||||||
} else {
|
} else {
|
||||||
@ -110,41 +191,36 @@ class FlutterBinding extends HitTestTarget {
|
|||||||
/// State for all pointers which are currently down.
|
/// State for all pointers which are currently down.
|
||||||
/// We do not track the state of hovering pointers because we need
|
/// We do not track the state of hovering pointers because we need
|
||||||
/// to hit-test them on each movement.
|
/// to hit-test them on each movement.
|
||||||
Map<int, _PointerState> _stateForPointer = new Map<int, _PointerState>();
|
Map<int, HitTestResult> _resultForPointer = new Map<int, HitTestResult>();
|
||||||
|
|
||||||
void _handlePointerInputEvent(PointerInputEvent event) {
|
void _handlePointerInputEvent(PointerInputEvent event) {
|
||||||
Point position = new Point(event.x, event.y);
|
HitTestResult result = _resultForPointer[event.pointer];
|
||||||
|
|
||||||
_PointerState state = _stateForPointer[event.pointer];
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case 'pointerdown':
|
case 'pointerdown':
|
||||||
if (state == null) {
|
if (result == null) {
|
||||||
state = new _PointerState(result: hitTest(position), lastPosition: position);
|
result = hitTest(new Point(event.x, event.y));
|
||||||
_stateForPointer[event.pointer] = state;
|
_resultForPointer[event.pointer] = result;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'pointermove':
|
case 'pointermove':
|
||||||
if (state == null) {
|
if (result == null) {
|
||||||
// The pointer is hovering, ignore it for now since we don't
|
// The pointer is hovering, ignore it for now since we don't
|
||||||
// know what to do with it yet.
|
// know what to do with it yet.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
event.dx = position.x - state.lastPosition.x;
|
|
||||||
event.dy = position.y - state.lastPosition.y;
|
|
||||||
state.lastPosition = position;
|
|
||||||
break;
|
break;
|
||||||
case 'pointerup':
|
case 'pointerup':
|
||||||
case 'pointercancel':
|
case 'pointercancel':
|
||||||
if (state == null) {
|
if (result == null) {
|
||||||
// This seems to be a spurious event. Ignore it.
|
// This seems to be a spurious event. Ignore it.
|
||||||
return;
|
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)
|
if (_hammingWeight(event.buttons) <= 1)
|
||||||
_stateForPointer.remove(event.pointer);
|
_resultForPointer.remove(event.pointer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dispatchEvent(event, state.result);
|
dispatchEvent(event, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine which [HitTestTarget] objects are located at a given position
|
/// Determine which [HitTestTarget] objects are located at a given position
|
||||||
|
Loading…
x
Reference in New Issue
Block a user