update ThermionListenerWidget to use newer InputHandler interface
This commit is contained in:
@@ -3,10 +3,10 @@ import 'dart:io';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart' hide KeyEvent;
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
import 'package:thermion_dart/thermion_dart.dart' hide KeyEvent;
|
||||||
|
import 'package:thermion_dart/thermion_dart.dart' as t;
|
||||||
import 'package:thermion_flutter/src/widgets/src/pixel_ratio_aware.dart';
|
import 'package:thermion_flutter/src/widgets/src/pixel_ratio_aware.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
|
||||||
|
|
||||||
extension OffsetExtension on Offset {
|
extension OffsetExtension on Offset {
|
||||||
Vector2 toVector2() {
|
Vector2 toVector2() {
|
||||||
@@ -15,17 +15,18 @@ extension OffsetExtension on Offset {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Captures swipe/pointer events and forwards to the provided [InputHandler].
|
/// Forwards cross-platform touch/mouse events to an
|
||||||
|
/// [InputHandler].
|
||||||
///
|
///
|
||||||
class ThermionListenerWidget extends StatefulWidget {
|
class ThermionListenerWidget extends StatefulWidget {
|
||||||
///
|
|
||||||
/// The content to display below the gesture detector/listener widget.
|
/// The content to display below the gesture detector/listener widget.
|
||||||
/// This will usually be a ThermionWidget (so you can navigate by directly interacting with the viewport), but this is not necessary.
|
/// This will usually be a ThermionWidget (so you can navigate by directly
|
||||||
/// It is equally possible to render the viewport/gesture controls elsewhere in the widget hierarchy. The only requirement is that they share the same [FilamentViewer].
|
/// interacting with the viewport), but this is not necessary. It is equally
|
||||||
///
|
/// possible to render the viewport/gesture controls elsewhere in the widget
|
||||||
|
/// hierarchy.
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
|
|
||||||
///
|
/// A focus node for input events.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
final FocusNode? focusNode;
|
final FocusNode? focusNode;
|
||||||
@@ -35,6 +36,9 @@ class ThermionListenerWidget extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
final InputHandler inputHandler;
|
final InputHandler inputHandler;
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
const ThermionListenerWidget({
|
const ThermionListenerWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.inputHandler,
|
required this.inputHandler,
|
||||||
@@ -71,9 +75,9 @@ class _ThermionListenerWidgetState extends State<ThermionListenerWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event is KeyDownEvent || event is KeyRepeatEvent) {
|
if (event is KeyDownEvent || event is KeyRepeatEvent) {
|
||||||
widget.inputHandler.keyDown(key!);
|
widget.inputHandler.handle(t.KeyEvent(KeyEventType.down, key));
|
||||||
} else if (event is KeyUpEvent) {
|
} else if (event is KeyUpEvent) {
|
||||||
widget.inputHandler.keyUp(key!);
|
widget.inputHandler.handle(t.KeyEvent(KeyEventType.up, key));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -85,38 +89,64 @@ class _ThermionListenerWidgetState extends State<ThermionListenerWidget> {
|
|||||||
HardwareKeyboard.instance.removeHandler(_handleKeyEvent);
|
HardwareKeyboard.instance.removeHandler(_handleKeyEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.MouseButton? _mouseButtonFromEvent(PointerEvent event) {
|
||||||
|
t.MouseButton? button;
|
||||||
|
|
||||||
|
if (event.buttons & kMiddleMouseButton != 0) {
|
||||||
|
button = MouseButton.middle;
|
||||||
|
} else if (event.buttons & kPrimaryMouseButton != 0) {
|
||||||
|
button = MouseButton.left;
|
||||||
|
} else if (event.buttons & kSecondaryMouseButton != 0) {
|
||||||
|
button = MouseButton.right;
|
||||||
|
}
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
Widget _desktop(double pixelRatio) {
|
Widget _desktop(double pixelRatio) {
|
||||||
return Focus(
|
return Focus(
|
||||||
focusNode: widget.focusNode,
|
focusNode: widget.focusNode,
|
||||||
child: Listener(
|
child: Listener(
|
||||||
onPointerHover: (event) {
|
onPointerHover: (event) {
|
||||||
widget.inputHandler.onPointerHover(
|
widget.inputHandler.handle(MouseEvent(
|
||||||
|
MouseEventType.hover,
|
||||||
|
_mouseButtonFromEvent(event),
|
||||||
event.localPosition.toVector2() * pixelRatio,
|
event.localPosition.toVector2() * pixelRatio,
|
||||||
event.delta.toVector2() * pixelRatio);
|
event.delta.toVector2() * pixelRatio));
|
||||||
},
|
},
|
||||||
onPointerSignal: (PointerSignalEvent pointerSignal) {
|
onPointerSignal: (PointerSignalEvent pointerSignal) {
|
||||||
if (pointerSignal is PointerScrollEvent) {
|
if (pointerSignal is PointerScrollEvent) {
|
||||||
widget.inputHandler.onPointerScroll(
|
widget.inputHandler.handle(ScrollEvent(
|
||||||
pointerSignal.localPosition.toVector2() * pixelRatio,
|
localPosition:
|
||||||
pointerSignal.scrollDelta.dy * pixelRatio);
|
pointerSignal.localPosition.toVector2() * pixelRatio,
|
||||||
|
delta: pointerSignal.scrollDelta.dy * pixelRatio));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPointerPanZoomStart: (pzs) {
|
onPointerPanZoomStart: (pzs) {
|
||||||
throw Exception("TODO - is this a pinch zoom on laptop trackpad?");
|
throw Exception("TODO - is this a pinch zoom on laptop trackpad?");
|
||||||
},
|
},
|
||||||
onPointerDown: (d) {
|
onPointerDown: (event) {
|
||||||
widget.focusNode?.requestFocus();
|
widget.focusNode?.requestFocus();
|
||||||
widget.inputHandler.onPointerDown(
|
|
||||||
d.localPosition.toVector2() * pixelRatio,
|
widget.inputHandler.handle(MouseEvent(
|
||||||
d.buttons & kMiddleMouseButton != 0);
|
MouseEventType.buttonDown,
|
||||||
|
_mouseButtonFromEvent(event),
|
||||||
|
event.localPosition.toVector2() * pixelRatio,
|
||||||
|
event.delta.toVector2() * pixelRatio));
|
||||||
|
},
|
||||||
|
onPointerMove: (PointerMoveEvent event) {
|
||||||
|
widget.inputHandler.handle(MouseEvent(
|
||||||
|
MouseEventType.move,
|
||||||
|
_mouseButtonFromEvent(event),
|
||||||
|
event.localPosition.toVector2() * pixelRatio,
|
||||||
|
event.delta.toVector2() * pixelRatio));
|
||||||
|
},
|
||||||
|
onPointerUp: (event) {
|
||||||
|
widget.inputHandler.handle(MouseEvent(
|
||||||
|
MouseEventType.buttonUp,
|
||||||
|
_mouseButtonFromEvent(event),
|
||||||
|
event.localPosition.toVector2() * pixelRatio,
|
||||||
|
event.delta.toVector2() * pixelRatio));
|
||||||
},
|
},
|
||||||
onPointerMove: (PointerMoveEvent d) => widget.inputHandler
|
|
||||||
.onPointerMove(
|
|
||||||
d.localPosition.toVector2() * pixelRatio,
|
|
||||||
d.delta.toVector2() * pixelRatio,
|
|
||||||
d.buttons & kMiddleMouseButton != 0),
|
|
||||||
onPointerUp: (d) => widget.inputHandler
|
|
||||||
.onPointerUp(d.buttons & kMiddleMouseButton != 0),
|
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -131,16 +161,8 @@ class _ThermionListenerWidgetState extends State<ThermionListenerWidget> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return PixelRatioAware(builder: (ctx, pixelRatio) {
|
return PixelRatioAware(builder: (ctx, pixelRatio) {
|
||||||
return FutureBuilder(
|
return SizedBox.expand(
|
||||||
initialData: 1.0,
|
child: isDesktop ? _desktop(pixelRatio) : _mobile(pixelRatio));
|
||||||
future: widget.inputHandler.initialized,
|
|
||||||
builder: (_, initialized) {
|
|
||||||
if (initialized.data != true) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
return SizedBox.expand(
|
|
||||||
child: isDesktop ? _desktop(pixelRatio) : _mobile(pixelRatio));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,43 +184,52 @@ class _MobileListenerWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MobileListenerWidgetState extends State<_MobileListenerWidget> {
|
class _MobileListenerWidgetState extends State<_MobileListenerWidget> {
|
||||||
bool isPan = true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
behavior: HitTestBehavior.translucent,
|
behavior: HitTestBehavior.translucent,
|
||||||
onTapDown: (details) => widget.inputHandler.onPointerDown(
|
// onPanDown: (event) {
|
||||||
details.localPosition.toVector2() * widget.pixelRatio, false),
|
// print("PAN DOWN");
|
||||||
|
// },
|
||||||
|
// onTapMove: (event) {
|
||||||
|
// print("TAP MOVE");
|
||||||
|
// },
|
||||||
|
onTapDown: (details) {
|
||||||
|
widget.inputHandler.handle(TouchEvent(TouchEventType.tap,
|
||||||
|
details.localPosition.toVector2() * widget.pixelRatio, null));
|
||||||
|
},
|
||||||
onDoubleTap: () {
|
onDoubleTap: () {
|
||||||
widget.inputHandler.setActionForType(InputType.SCALE1,
|
widget.inputHandler
|
||||||
isPan ? InputAction.TRANSLATE : InputAction.ROTATE);
|
.handle(TouchEvent(TouchEventType.doubleTap, null, null));
|
||||||
},
|
},
|
||||||
onScaleStart: (details) async {
|
onScaleStart: (event) async {
|
||||||
await widget.inputHandler.onScaleStart(
|
widget.inputHandler.handle(ScaleStartEvent(
|
||||||
details.localFocalPoint.toVector2() * widget.pixelRatio,
|
numPointers: event.pointerCount,
|
||||||
details.pointerCount,
|
localFocalPoint: (
|
||||||
details.sourceTimeStamp);
|
event.focalPoint.dx * widget.pixelRatio,
|
||||||
|
event.focalPoint.dy * widget.pixelRatio
|
||||||
|
)));
|
||||||
},
|
},
|
||||||
onScaleUpdate: (ScaleUpdateDetails details) async {
|
onScaleUpdate: (ScaleUpdateDetails event) async {
|
||||||
await widget.inputHandler.onScaleUpdate(
|
widget.inputHandler.handle(ScaleUpdateEvent(
|
||||||
details.localFocalPoint.toVector2() * widget.pixelRatio,
|
numPointers: event.pointerCount,
|
||||||
details.focalPointDelta.toVector2() * widget.pixelRatio,
|
localFocalPoint: (
|
||||||
details.horizontalScale,
|
event.focalPoint.dx * widget.pixelRatio,
|
||||||
details.verticalScale,
|
event.focalPoint.dy * widget.pixelRatio
|
||||||
details.scale,
|
),
|
||||||
details.pointerCount,
|
localFocalPointDelta: (
|
||||||
details.rotation,
|
event.focalPointDelta.dx * widget.pixelRatio,
|
||||||
details.sourceTimeStamp);
|
event.focalPointDelta.dy * widget.pixelRatio
|
||||||
|
),
|
||||||
|
rotation: event.rotation,
|
||||||
|
horizontalScale: event.horizontalScale,
|
||||||
|
verticalScale: event.verticalScale,
|
||||||
|
scale: event.scale,
|
||||||
|
));
|
||||||
},
|
},
|
||||||
onScaleEnd: (details) async {
|
onScaleEnd: (details) async {
|
||||||
await widget.inputHandler
|
widget.inputHandler
|
||||||
.onScaleEnd(details.pointerCount, details.scaleVelocity);
|
.handle(ScaleEndEvent(numPointers: details.pointerCount));
|
||||||
},
|
},
|
||||||
child: widget.child);
|
child: widget.child);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user