allow zooming on desktop when holding ctrl and scrolling
add prototype of selection mode, span up dashed rectangle
This commit is contained in:
		| @@ -2,6 +2,7 @@ import 'dart:ui'; | |||||||
|  |  | ||||||
| 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:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||||
|  |  | ||||||
| import '../context/file_change_notifier.dart'; | import '../context/file_change_notifier.dart'; | ||||||
| @@ -151,8 +152,17 @@ class _DrawingPageState extends State<DrawingPage> { | |||||||
|         debugPrint('got pointer signal: $pointerSignal'); |         debugPrint('got pointer signal: $pointerSignal'); | ||||||
|  |  | ||||||
|         if (pointerSignal is PointerScrollEvent) { |         if (pointerSignal is PointerScrollEvent) { | ||||||
|  |           final bool ctrlPressed = RawKeyboard.instance.keysPressed | ||||||
|  |               .contains(LogicalKeyboardKey.controlLeft); | ||||||
|  |  | ||||||
|           final delta = pointerSignal.scrollDelta; |           final delta = pointerSignal.scrollDelta; | ||||||
|           _calcNewPageOffset(-delta, size.width); |           if (ctrlPressed) { | ||||||
|  |             setState(() { | ||||||
|  |               zoom = (zoom - delta.dy.sign * .1).clamp(0.25, 5.0); | ||||||
|  |             }); | ||||||
|  |           } else { | ||||||
|  |             _calcNewPageOffset(-delta, size.width); | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|       }, |       }, | ||||||
|       onPointerDown: (d) { |       onPointerDown: (d) { | ||||||
|   | |||||||
| @@ -3,6 +3,8 @@ import 'dart:math'; | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| import 'paint_controller.dart'; | import 'paint_controller.dart'; | ||||||
|  | import 'path/path_transform.dart'; | ||||||
|  | import 'path/ring_number_provider.dart'; | ||||||
| import 'screen_document_mapping.dart'; | import 'screen_document_mapping.dart'; | ||||||
|  |  | ||||||
| final Rect a4Page = | final Rect a4Page = | ||||||
| @@ -81,18 +83,37 @@ class MyPainter extends CustomPainter { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // active eraser outline |     // active pen hover effects | ||||||
|     if (activePen == Pen.eraser) { |     switch (activePen) { | ||||||
|       final pointerpos = controller.getPointerPosition(); |       case Pen.eraser: | ||||||
|       if (pointerpos != null) { |         final pointerpos = controller.getPointerPosition(); | ||||||
|         final translatedPointerpos = _translatept(pointerpos, size); |         if (pointerpos != null) { | ||||||
|         canvas.drawCircle( |           final translatedPointerpos = _translatept(pointerpos, size); | ||||||
|             translatedPointerpos, |           canvas.drawCircle( | ||||||
|             calcPageDependentScale(zoom, a4Page, canvasSize) * 2.0, |               translatedPointerpos, | ||||||
|             paint |               calcPageDependentScale(zoom, a4Page, canvasSize) * 2.0, | ||||||
|               ..style = PaintingStyle.stroke |               paint | ||||||
|               ..color = Colors.grey); |                 ..style = PaintingStyle.stroke | ||||||
|       } |                 ..color = Colors.grey); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       case Pen.selector: | ||||||
|  |         final selection = controller.getSelection(); | ||||||
|  |         if (selection != null) { | ||||||
|  |           final rectpath = (Path() | ||||||
|  |                 ..addRect(Rect.fromPoints(_translatept(selection.topLeft, size), | ||||||
|  |                     _translatept(selection.bottomRight, size)))) | ||||||
|  |               .dashPath(RingNumberProvider([3, 5])); | ||||||
|  |  | ||||||
|  |           canvas.drawPath( | ||||||
|  |               rectpath, | ||||||
|  |               paint | ||||||
|  |                 ..style = PaintingStyle.stroke | ||||||
|  |                 ..color = Colors.grey); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ class PaintController extends ChangeNotifier { | |||||||
|   Offset? _currentPointerPosition; |   Offset? _currentPointerPosition; | ||||||
|   Pen activePen = Pen.pen; |   Pen activePen = Pen.pen; | ||||||
|   List<Stroke> strokes = []; |   List<Stroke> strokes = []; | ||||||
|  |   Offset? _selectionStart; | ||||||
|  |  | ||||||
|   PaintController(this.file); |   PaintController(this.file); | ||||||
|  |  | ||||||
| @@ -37,38 +38,59 @@ class PaintController extends ChangeNotifier { | |||||||
|       // todo line drawn on edge where line left page |       // todo line drawn on edge where line left page | ||||||
|       if (!a4Page.contains(offset)) return; |       if (!a4Page.contains(offset)) return; | ||||||
|  |  | ||||||
|       // todo handle other pens |       switch (activePen) { | ||||||
|       if (activePen == Pen.eraser || activePen == Pen.selector) return; |         case Pen.pen: | ||||||
|  |         case Pen.highlighter: | ||||||
|       int strokeid = strokes.isNotEmpty ? strokes.last.id + 1 : 0; |           int strokeid = strokes.isNotEmpty ? strokes.last.id + 1 : 0; | ||||||
|       final color = activePen == Pen.pen |           final color = activePen == Pen.pen | ||||||
|           ? const Color(0xFF444444) |               ? const Color(0xFF444444) | ||||||
|           : Colors.yellow.withOpacity(.3); |               : Colors.yellow.withOpacity(.3); | ||||||
|       strokes.add(Stroke.fromPoints( |           strokes.add(Stroke.fromPoints( | ||||||
|           [Point(offset, _calcTiltedWidth(3.0, e.tilt))], strokeid, color)); |               [Point(offset, _calcTiltedWidth(3.0, e.tilt))], strokeid, color)); | ||||||
|       file.addStroke(strokeid, color); |           file.addStroke(strokeid, color); | ||||||
|       notifyListeners(); |           notifyListeners(); | ||||||
|  |           break; | ||||||
|  |         case Pen.selector: | ||||||
|  |           _selectionStart = offset; | ||||||
|  |           break; | ||||||
|  |         default: | ||||||
|  |           break; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   Rect? getSelection() { | ||||||
|  |     if (_currentPointerPosition == null || _selectionStart == null) return null; | ||||||
|  |     return Rect.fromPoints(_selectionStart!, _currentPointerPosition!); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   void pointUpEvent(PointerUpEvent e) { |   void pointUpEvent(PointerUpEvent e) { | ||||||
|     _currentPointerPosition = null; |     _currentPointerPosition = null; | ||||||
|     notifyListeners(); |     notifyListeners(); | ||||||
|  |  | ||||||
|     if (activePen == Pen.eraser) return; |     switch (activePen) { | ||||||
|  |       case Pen.pen: | ||||||
|     // pointerupevent doesn't deliver correct event button |       case Pen.highlighter: | ||||||
|     if (_allowedToDraw(e.kind, 1)) { |         // pointerupevent doesn't deliver correct event button | ||||||
|       final lastStroke = strokes.last; |         if (_allowedToDraw(e.kind, 1)) { | ||||||
|       if (lastStroke.points.length <= 1) { |           final lastStroke = strokes.last; | ||||||
|         // if the line consists only of one point (point) add endpoint as the same to allow drawing a line |           if (lastStroke.points.length <= 1) { | ||||||
|         lastStroke.points.add(lastStroke.points.last); |             // if the line consists only of one point (point) add endpoint as the same to allow drawing a line | ||||||
|         file.addPoint(lastStroke.id, lastStroke.points.last); |             lastStroke.points.add(lastStroke.points.last); | ||||||
|         notifyListeners(); |             file.addPoint(lastStroke.id, lastStroke.points.last); | ||||||
|       } else { |             notifyListeners(); | ||||||
|         debugPrint('adding points to db'); |           } else { | ||||||
|         file.addPoints(lastStroke.id, lastStroke.points); |             debugPrint('adding points to db'); | ||||||
|       } |             file.addPoints(lastStroke.id, lastStroke.points); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       case Pen.selector: | ||||||
|  |         _selectionStart = null; | ||||||
|  |         // todo highlight current selection | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								lib/canvas/path/path_transform.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								lib/canvas/path/path_transform.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import 'dart:ui'; | ||||||
|  |  | ||||||
|  | import 'ring_number_provider.dart'; | ||||||
|  |  | ||||||
|  | extension DashPath on Path { | ||||||
|  |   // creates a new dashed path with the given intervals | ||||||
|  |   Path dashPath(RingNumberProvider dashArray) { | ||||||
|  |     final Path dest = Path(); | ||||||
|  |     for (final PathMetric metric in computeMetrics()) { | ||||||
|  |       double distance = .0; | ||||||
|  |       bool draw = true; | ||||||
|  |       while (distance < metric.length) { | ||||||
|  |         final double len = dashArray.next; | ||||||
|  |         if (draw) { | ||||||
|  |           dest.addPath( | ||||||
|  |               metric.extractPath(distance, distance + len), Offset.zero); | ||||||
|  |         } | ||||||
|  |         distance += len; | ||||||
|  |         draw = !draw; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return dest; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								lib/canvas/path/ring_number_provider.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								lib/canvas/path/ring_number_provider.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | class RingNumberProvider { | ||||||
|  |   RingNumberProvider(this._vals); | ||||||
|  |  | ||||||
|  |   final List<double> _vals; | ||||||
|  |   int _idx = 0; | ||||||
|  |  | ||||||
|  |   double get next { | ||||||
|  |     if (_idx >= _vals.length) { | ||||||
|  |       _idx = 0; | ||||||
|  |     } | ||||||
|  |     return _vals[_idx++]; | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user