diff --git a/lib/canvas/my_painter.dart b/lib/canvas/my_painter.dart index 3ed4786..da2096a 100644 --- a/lib/canvas/my_painter.dart +++ b/lib/canvas/my_painter.dart @@ -80,6 +80,20 @@ class MyPainter extends CustomPainter { } } } + + // active eraser outline + if (activePen == Pen.eraser) { + final pointerpos = controller.getPointerPosition(); + if (pointerpos != null) { + final translatedPointerpos = _translatept(pointerpos, size); + canvas.drawCircle( + translatedPointerpos, + calcPageDependentScale(zoom, a4Page, canvasSize) * 2.0, + paint + ..style = PaintingStyle.stroke + ..color = Colors.grey); + } + } } @override diff --git a/lib/canvas/paint_controller.dart b/lib/canvas/paint_controller.dart index 4d31516..023cd10 100644 --- a/lib/canvas/paint_controller.dart +++ b/lib/canvas/paint_controller.dart @@ -12,45 +12,24 @@ import 'my_painter.dart'; enum Pen { eraser, pen, highlighter, selector } class PaintController extends ChangeNotifier { + final bool _allowDrawWithFinger = false; + final NoteFile file; + + Offset? _currentPointerPosition; Pen activePen = Pen.pen; List strokes = []; - final bool _allowDrawWithFinger = false; PaintController(this.file); - final NoteFile file; - void changePen(Pen pen) { activePen = pen; notifyListeners(); } - double _calcTiltedWidth(double baseWidth, double tilt) { - if (tilt == .0) return baseWidth; - return baseWidth * tilt; - } - - double _calcAngleDependentWidth(Point pt1, Point pt2, double basetickness) { - final delta = pt2.point - pt1.point; - final normalizedDelta = - delta / sqrt(delta.dx * delta.dx + delta.dy * delta.dy); - - double alpha = asin(normalizedDelta.dy); - // range [-pi,pi] - alpha += (3 * pi / 4); - // range [0,inf] - alpha = alpha % (2 * pi); - // range [0,2pi] - alpha -= pi; - // range [-pi,pi] - alpha = alpha.abs(); - // range [0,pi] - alpha /= pi; - // range [0,1] - alpha += .5; - // range [.5,1.5] - - return basetickness * alpha; + /// return current position of pointer + /// null if nowhere hovering or painting + Offset? getPointerPosition() { + return _currentPointerPosition; } void pointDownEvent(Offset offset, PointerDownEvent e) async { @@ -73,6 +52,9 @@ class PaintController extends ChangeNotifier { } void pointUpEvent(PointerUpEvent e) { + _currentPointerPosition = null; + notifyListeners(); + if (activePen == Pen.eraser) return; // pointerupevent doesn't deliver correct event button @@ -90,14 +72,9 @@ class PaintController extends ChangeNotifier { } } - /// check if pointer event is allowed to draw points - bool _allowedToDraw(PointerDeviceKind kind, int button) { - return (_allowDrawWithFinger && kind == PointerDeviceKind.touch) || - kind == PointerDeviceKind.stylus || - (kind == PointerDeviceKind.mouse && button == kPrimaryMouseButton); - } - void pointMoveEvent(Offset offset, PointerMoveEvent event) { + _currentPointerPosition = offset; + if (!a4Page.contains(offset)) { return; } @@ -106,10 +83,10 @@ class PaintController extends ChangeNotifier { switch (activePen) { case Pen.eraser: // todo dynamic eraser size - final eraserrect = Rect.fromCircle(center: offset, radius: 3); + final eraserrect = Rect.fromCircle(center: offset, radius: 2.0); for (final stroke in strokes) { // check if delete action was within bounding rect of stroke - if (stroke.getBoundingRect().contains(offset)) { + if (stroke.getBoundingRect().overlaps(eraserrect)) { // check if eraser hit an point within its range for (final pt in stroke.points) { if (eraserrect.contains(pt.point)) { @@ -155,4 +132,39 @@ class PaintController extends ChangeNotifier { debugPrint('finished loading strokes from file'); notifyListeners(); } + + /// check if pointer event is allowed to draw points + bool _allowedToDraw(PointerDeviceKind kind, int button) { + return (_allowDrawWithFinger && kind == PointerDeviceKind.touch) || + kind == PointerDeviceKind.stylus || + (kind == PointerDeviceKind.mouse && button == kPrimaryMouseButton); + } + + double _calcAngleDependentWidth(Point pt1, Point pt2, double basetickness) { + final delta = pt2.point - pt1.point; + final normalizedDelta = + delta / sqrt(delta.dx * delta.dx + delta.dy * delta.dy); + + double alpha = asin(normalizedDelta.dy); + // range [-pi,pi] + alpha += (3 * pi / 4); + // range [0,inf] + alpha = alpha % (2 * pi); + // range [0,2pi] + alpha -= pi; + // range [-pi,pi] + alpha = alpha.abs(); + // range [0,pi] + alpha /= pi; + // range [0,1] + alpha += .5; + // range [.5,1.5] + + return basetickness * alpha; + } + + double _calcTiltedWidth(double baseWidth, double tilt) { + if (tilt == .0) return baseWidth; + return baseWidth * tilt; + } } diff --git a/lib/pages/all_notes_page.dart b/lib/pages/all_notes_page.dart index b452fe4..e294f25 100644 --- a/lib/pages/all_notes_page.dart +++ b/lib/pages/all_notes_page.dart @@ -209,48 +209,75 @@ class _AllNotesPageState extends State { Widget _buildNoteTiles() { return Consumer( builder: (BuildContext context, value, Widget? child) { - return Expanded( - child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 6, childAspectRatio: 0.7), - physics: const ScrollPhysics(), - padding: const EdgeInsets.all(2), - itemBuilder: (BuildContext context, int idx) => NoteTile( - data: value.tiledata[idx], - selectionMode: selectionMode, - selected: selectionIdx.contains(idx), - onSelectionChange: (selection) { - if (selection) { - if (!selectionMode) { - setState(() { - selectionMode = true; - }); - } - if (!selectionIdx.contains(idx)) { + if (value.tiledata.isEmpty) { + return _buildNoNotesText(); + } else { + return Expanded( + child: GridView.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 6, childAspectRatio: 0.7), + physics: const ScrollPhysics(), + padding: const EdgeInsets.all(2), + itemBuilder: (BuildContext context, int idx) => NoteTile( + data: value.tiledata[idx], + selectionMode: selectionMode, + selected: selectionIdx.contains(idx), + onSelectionChange: (selection) { + if (selection) { + if (!selectionMode) { + setState(() { + selectionMode = true; + }); + } + if (!selectionIdx.contains(idx)) { + final sel = selectionIdx; + sel.add(idx); + setState(() { + selectionIdx = sel; + }); + } + } else { final sel = selectionIdx; - sel.add(idx); + sel.remove(idx); + if (sel.isEmpty) { + setState(() { + selectionMode = false; + }); + } setState(() { selectionIdx = sel; }); } - } else { - final sel = selectionIdx; - sel.remove(idx); - if (sel.isEmpty) { - setState(() { - selectionMode = false; - }); - } - setState(() { - selectionIdx = sel; - }); - } - }, + }, + ), + itemCount: value.tiledata.length, ), - itemCount: value.tiledata.length, - ), - ); + ); + } }, ); } + + Widget _buildNoNotesText() { + return Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + Text( + 'No notes', + style: TextStyle( + color: Color.fromRGBO(255, 255, 255, .75), fontSize: 14), + ), + SizedBox( + height: 10, + ), + Text( + 'Tap the Add Button to create a note.', + style: TextStyle( + color: Color.fromRGBO(255, 255, 255, .65), fontSize: 12), + ) + ], + ), + ); + } }