From 6d1e56caacbfb2cbe2ec8686d192d98683d66678 Mon Sep 17 00:00:00 2001 From: Nick Fisher Date: Fri, 11 Oct 2024 15:37:03 +0800 Subject: [PATCH] mobile gesture handler --- .../input/src/delegate_gesture_handler.dart | 36 ++++++++++---- .../lib/src/input/src/input_handler.dart | 6 +-- .../widgets/src/thermion_listener_widget.dart | 47 +++++++++++-------- 3 files changed, 58 insertions(+), 31 deletions(-) diff --git a/thermion_dart/lib/src/input/src/delegate_gesture_handler.dart b/thermion_dart/lib/src/input/src/delegate_gesture_handler.dart index f994d533..5a53ed19 100644 --- a/thermion_dart/lib/src/input/src/delegate_gesture_handler.dart +++ b/thermion_dart/lib/src/input/src/delegate_gesture_handler.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:math'; import 'package:logging/logging.dart'; import 'package:thermion_dart/thermion_dart.dart'; import 'package:vector_math/vector_math_64.dart'; @@ -26,6 +27,8 @@ class DelegateInputHandler implements InputHandler { Map _actions = { InputType.LMB_HOLD_AND_MOVE: InputAction.TRANSLATE, + InputType.SCALE1: InputAction.TRANSLATE, + InputType.SCALE2: InputAction.ZOOM, InputType.MMB_HOLD_AND_MOVE: InputAction.ROTATE, InputType.SCROLLWHEEL: InputAction.TRANSLATE, InputType.POINTER_MOVE: InputAction.NONE, @@ -99,6 +102,8 @@ class DelegateInputHandler implements InputHandler { InputType.KEYDOWN_W: InputAction.TRANSLATE, InputType.KEYDOWN_S: InputAction.TRANSLATE, InputType.KEYDOWN_D: InputAction.TRANSLATE, + InputType.SCALE1: InputAction.TRANSLATE, + InputType.SCALE2: InputAction.ZOOM, if (freeLook) InputType.POINTER_MOVE: InputAction.ROTATE, }); @@ -235,15 +240,6 @@ class DelegateInputHandler implements InputHandler { @override Future get initialized => viewer.initialized; - @override - Future onScaleEnd() async {} - - @override - Future onScaleStart() async {} - - @override - Future onScaleUpdate() async {} - @override void setActionForType(InputType gestureType, InputAction gestureAction) { _actions[gestureType] = gestureAction; @@ -261,4 +257,26 @@ class DelegateInputHandler implements InputHandler { void keyUp(PhysicalKey key) { _pressedKeys.remove(key); } + + @override + Future onScaleEnd(int pointerCount) async {} + + @override + Future onScaleStart(Vector2 localPosition, int pointerCount) async { + // noop + } + + @override + Future onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta, + double horizontalScale, double verticalScale, double scale, int pointerCount) async { + if (pointerCount == 1) { + _inputDeltas[InputType.SCALE1] = + Vector3(focalPointDelta.x, focalPointDelta.y, 0); + } else if (pointerCount == 2) { + _inputDeltas[InputType.SCALE2] = + Vector3(0, 0, max(horizontalScale, verticalScale)); + } else { + throw UnimplementedError("Only pointerCount <= 2 supported"); + } + } } diff --git a/thermion_dart/lib/src/input/src/input_handler.dart b/thermion_dart/lib/src/input/src/input_handler.dart index 71593b21..90983d48 100644 --- a/thermion_dart/lib/src/input/src/input_handler.dart +++ b/thermion_dart/lib/src/input/src/input_handler.dart @@ -35,9 +35,9 @@ abstract class InputHandler { Future onPointerMove( Vector2 localPosition, Vector2 delta, bool isMiddle); Future onPointerUp(bool isMiddle); - Future onScaleStart(); - Future onScaleUpdate(); - Future onScaleEnd(); + Future onScaleStart(Vector2 focalPoint, int pointerCount); + Future onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta, double horizontalScale, double verticalScale, double scale, int pointerCount); + Future onScaleEnd(int pointerCount); Future get initialized; Future dispose(); diff --git a/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_listener_widget.dart b/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_listener_widget.dart index 262da5fd..2f6042e6 100644 --- a/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_listener_widget.dart +++ b/thermion_flutter/thermion_flutter/lib/src/widgets/src/thermion_listener_widget.dart @@ -110,7 +110,7 @@ class _ThermionListenerWidgetState extends State { Widget _mobile(double pixelRatio) { return _MobileListenerWidget( - gestureHandler: widget.gestureHandler, pixelRatio: pixelRatio); + gestureHandler: widget.gestureHandler, pixelRatio: pixelRatio, child:widget.child); } @override @@ -135,8 +135,10 @@ class _ThermionListenerWidgetState extends State { class _MobileListenerWidget extends StatefulWidget { final InputHandler gestureHandler; final double pixelRatio; + final Widget? child; - const _MobileListenerWidget({Key? key, required this.gestureHandler, required this.pixelRatio}) + const _MobileListenerWidget( + {Key? key, required this.gestureHandler, required this.pixelRatio, this.child}) : super(key: key); @override @@ -154,22 +156,29 @@ class _MobileListenerWidgetState extends State<_MobileListenerWidget> { @override Widget build(BuildContext context) { return GestureDetector( - behavior: HitTestBehavior.translucent, - onTapDown: (details) => widget.gestureHandler - .onPointerDown(details.localPosition.toVector2() * widget.pixelRatio, false), - onDoubleTap: () { - widget.gestureHandler.setActionForType(InputType.SCALE1, - isPan ? InputAction.TRANSLATE : InputAction.ROTATE); - }, - onScaleStart: (details) async { - await widget.gestureHandler.onScaleStart(); - }, - onScaleUpdate: (details) async { - await widget.gestureHandler.onScaleUpdate(); - }, - onScaleEnd: (details) async { - await widget.gestureHandler.onScaleUpdate(); - }, - ); + behavior: HitTestBehavior.translucent, + onTapDown: (details) => widget.gestureHandler.onPointerDown( + details.localPosition.toVector2() * widget.pixelRatio, false), + onDoubleTap: () { + widget.gestureHandler.setActionForType(InputType.SCALE1, + isPan ? InputAction.TRANSLATE : InputAction.ROTATE); + }, + onScaleStart: (details) async { + await widget.gestureHandler.onScaleStart( + details.localFocalPoint.toVector2(), details.pointerCount); + }, + onScaleUpdate: (ScaleUpdateDetails details) async { + await widget.gestureHandler.onScaleUpdate( + details.localFocalPoint.toVector2(), + details.focalPointDelta.toVector2(), + details.horizontalScale, + details.verticalScale, + details.scale, + details.pointerCount); + }, + onScaleEnd: (details) async { + await widget.gestureHandler.onScaleEnd(details.pointerCount); + }, + child: widget.child); } }