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 126bdb27..8f8f6918 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, ), (_) {}, ), @@ -82,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). @@ -105,11 +109,24 @@ 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; } + /// 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; + DrawableIsDrawingStateChangedNotification(false).dispatch(context); + } + Offset _globalToLocal(Offset globalPosition) { final getBox = context.findRenderObject() as RenderBox; @@ -123,11 +140,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 +171,10 @@ class _DragGestureDetector extends OneSequenceGestureRecognizer { onHorizontalDragUp(); stopTrackingPointer(event.pointer); _isTrackingGesture = false; + } else if (event is PointerCancelEvent) { + onHorizontalDragCancel(); + stopTrackingPointer(event.pointer); + _isTrackingGesture = false; } }