From f3d73c84ea5b1e8d479d766756aadb0125d0a275 Mon Sep 17 00:00:00 2001 From: Ollis Laptop Date: Thu, 11 May 2023 22:39:24 +0200 Subject: [PATCH 1/2] support PointerCancelEvent Event cancels the potentially already active gesture --- lib/src/views/widgets/free_style_widget.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/src/views/widgets/free_style_widget.dart b/lib/src/views/widgets/free_style_widget.dart index 126bdb27..b041e67c 100644 --- a/lib/src/views/widgets/free_style_widget.dart +++ b/lib/src/views/widgets/free_style_widget.dart @@ -35,6 +35,7 @@ class _FreeStyleWidgetState extends State<_FreeStyleWidget> { onHorizontalDragDown: _handleHorizontalDragDown, onHorizontalDragUpdate: _handleHorizontalDragUpdate, onHorizontalDragUp: _handleHorizontalDragUp, + onHorizontalDragCancel: _handleHorizontalDragCancel, ), (_) {}, ), @@ -110,6 +111,16 @@ class _FreeStyleWidgetState extends State<_FreeStyleWidget> { drawable = null; } + /// Callback when the pointer event was falsely directed to us. + /// E.g. when the wrist was layed on the pad, but then a pen is recognized. + /// => the painting input of the wrist is invalid! + void _handleHorizontalDragCancel() { + if (drawable != null && drawable is PathDrawable) { + PainterController.of(context).removeDrawable(drawable!); + } + drawable = null; + } + Offset _globalToLocal(Offset globalPosition) { final getBox = context.findRenderObject() as RenderBox; @@ -123,11 +134,13 @@ class _DragGestureDetector extends OneSequenceGestureRecognizer { required this.onHorizontalDragDown, required this.onHorizontalDragUpdate, required this.onHorizontalDragUp, + required this.onHorizontalDragCancel, }); final ValueSetter onHorizontalDragDown; final ValueSetter onHorizontalDragUpdate; final VoidCallback onHorizontalDragUp; + final VoidCallback onHorizontalDragCancel; bool _isTrackingGesture = false; @@ -152,6 +165,10 @@ class _DragGestureDetector extends OneSequenceGestureRecognizer { onHorizontalDragUp(); stopTrackingPointer(event.pointer); _isTrackingGesture = false; + } else if (event is PointerCancelEvent) { + onHorizontalDragCancel(); + stopTrackingPointer(event.pointer); + _isTrackingGesture = false; } } From bfb3583551a04241d321b9bcea69c22d8e7d4510 Mon Sep 17 00:00:00 2001 From: Tobias Bodmer Date: Sat, 13 May 2023 16:33:58 +0200 Subject: [PATCH 2/2] add onIsDrawingStateChanged callback is fired every time the user starts or stops freehand drawing. Useful if the painter widget is in a scrollable environment --- .../is_drawing_state_changed.dart | 10 +++ lib/src/views/widgets/flutter_painter.dart | 63 +++++++++++-------- lib/src/views/widgets/free_style_widget.dart | 6 ++ 3 files changed, 54 insertions(+), 25 deletions(-) create mode 100644 lib/src/controllers/notifications/is_drawing_state_changed.dart diff --git a/lib/src/controllers/notifications/is_drawing_state_changed.dart b/lib/src/controllers/notifications/is_drawing_state_changed.dart new file mode 100644 index 00000000..f9c00ab1 --- /dev/null +++ b/lib/src/controllers/notifications/is_drawing_state_changed.dart @@ -0,0 +1,10 @@ +import 'notification.dart'; + +/// A notification that is dispatched when the user starts or stops freehand painting +class DrawableIsDrawingStateChangedNotification + extends FlutterPainterNotification { + bool isDrawing; + + /// Creates a [DrawableIsDrawingStateChangedNotification]. Supplies the current Drawable and also if the user started or stopped + DrawableIsDrawingStateChangedNotification(this.isDrawing); +} diff --git a/lib/src/views/widgets/flutter_painter.dart b/lib/src/views/widgets/flutter_painter.dart index 201af62d..38bde300 100644 --- a/lib/src/views/widgets/flutter_painter.dart +++ b/lib/src/views/widgets/flutter_painter.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter_painter/src/controllers/notifications/is_drawing_state_changed.dart'; import '../../controllers/events/selected_object_drawable_removed_event.dart'; import '../../controllers/helpers/renderer_check/renderer_check.dart'; import '../../controllers/drawables/drawable.dart'; @@ -54,6 +55,9 @@ class FlutterPainter extends StatelessWidget { /// Callback when the [PainterSettings] of [PainterController] are updated internally. final ValueChanged? onPainterSettingsChanged; + /// Callback when a [FreeStyleDrawable] starts or stops being drawn + final ValueChanged? onIsDrawingStateChanged; + /// The builder used to build this widget. /// /// Using the default constructor, it will default to returning the [_FlutterPainterWidget]. @@ -63,29 +67,31 @@ class FlutterPainter extends StatelessWidget { final FlutterPainterBuilderCallback _builder; /// Creates a [FlutterPainter] with the given [controller] and optional callbacks. - const FlutterPainter( - {Key? key, - required this.controller, - this.onDrawableCreated, - this.onDrawableDeleted, - this.onSelectedObjectDrawableChanged, - this.onPainterSettingsChanged}) - : _builder = _defaultBuilder, + const FlutterPainter({ + Key? key, + required this.controller, + this.onDrawableCreated, + this.onDrawableDeleted, + this.onSelectedObjectDrawableChanged, + this.onPainterSettingsChanged, + this.onIsDrawingStateChanged, + }) : _builder = _defaultBuilder, super(key: key); /// Creates a [FlutterPainter] with the given [controller], [builder] and optional callbacks. /// /// Using this constructor, the [builder] will be called any time the [controller] updates. /// It is useful if you want to build UI that automatically rebuilds on updates from [controller]. - const FlutterPainter.builder( - {Key? key, - required this.controller, - required FlutterPainterBuilderCallback builder, - this.onDrawableCreated, - this.onDrawableDeleted, - this.onSelectedObjectDrawableChanged, - this.onPainterSettingsChanged}) - : _builder = builder, + const FlutterPainter.builder({ + Key? key, + required this.controller, + required FlutterPainterBuilderCallback builder, + this.onDrawableCreated, + this.onDrawableDeleted, + this.onSelectedObjectDrawableChanged, + this.onPainterSettingsChanged, + this.onIsDrawingStateChanged, + }) : _builder = builder, super(key: key); @override @@ -105,6 +111,7 @@ class FlutterPainter extends StatelessWidget { onPainterSettingsChanged: onPainterSettingsChanged, onSelectedObjectDrawableChanged: onSelectedObjectDrawableChanged, + onIsDrawingStateChanged: onIsDrawingStateChanged, )); }), ); @@ -133,15 +140,19 @@ class _FlutterPainterWidget extends StatelessWidget { /// Callback when the [PainterSettings] of [PainterController] are updated internally. final ValueChanged? onPainterSettingsChanged; + /// Callback when a [FreeStyleDrawable] starts or stops being drawn + final ValueChanged? onIsDrawingStateChanged; + /// Creates a [_FlutterPainterWidget] with the given [controller] and optional callbacks. - const _FlutterPainterWidget( - {Key? key, - required this.controller, - this.onDrawableCreated, - this.onDrawableDeleted, - this.onSelectedObjectDrawableChanged, - this.onPainterSettingsChanged}) - : super(key: key); + const _FlutterPainterWidget({ + Key? key, + required this.controller, + this.onDrawableCreated, + this.onDrawableDeleted, + this.onSelectedObjectDrawableChanged, + this.onPainterSettingsChanged, + this.onIsDrawingStateChanged, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -197,6 +208,8 @@ class _FlutterPainterWidget extends StatelessWidget { onSelectedObjectDrawableChanged?.call(notification.drawable); } else if (notification is SettingsUpdatedNotification) { onPainterSettingsChanged?.call(notification.settings); + } else if (notification is DrawableIsDrawingStateChangedNotification) { + onIsDrawingStateChanged?.call(notification.isDrawing); } return true; } diff --git a/lib/src/views/widgets/free_style_widget.dart b/lib/src/views/widgets/free_style_widget.dart index b041e67c..8f8f6918 100644 --- a/lib/src/views/widgets/free_style_widget.dart +++ b/lib/src/views/widgets/free_style_widget.dart @@ -83,6 +83,9 @@ class _FreeStyleWidgetState extends State<_FreeStyleWidget> { // Set the drawable as the current drawable this.drawable = drawable; + + // notify that we now start drawing + DrawableIsDrawingStateChangedNotification(true).dispatch(context); } /// Callback when the user moves, rotates or scales the pointer(s). @@ -106,6 +109,8 @@ class _FreeStyleWidgetState extends State<_FreeStyleWidget> { /// Callback when the user removes all pointers from the widget. void _handleHorizontalDragUp() { DrawableCreatedNotification(drawable).dispatch(context); + // notify that we now start drawing + DrawableIsDrawingStateChangedNotification(false).dispatch(context); /// Reset the current drawable for the user to draw a new one next time drawable = null; @@ -119,6 +124,7 @@ class _FreeStyleWidgetState extends State<_FreeStyleWidget> { PainterController.of(context).removeDrawable(drawable!); } drawable = null; + DrawableIsDrawingStateChangedNotification(false).dispatch(context); } Offset _globalToLocal(Offset globalPosition) {