allow zooming on desktop when holding ctrl and scrolling

add prototype of selection mode, span up dashed rectangle
This commit is contained in:
lukas-heiligenbrunner 2022-12-02 00:25:37 +01:00
parent 4899381510
commit 8e0cd05ded
5 changed files with 129 additions and 38 deletions

View File

@ -2,6 +2,7 @@ import 'dart:ui';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../context/file_change_notifier.dart';
@ -151,8 +152,17 @@ class _DrawingPageState extends State<DrawingPage> {
debugPrint('got pointer signal: $pointerSignal');
if (pointerSignal is PointerScrollEvent) {
final bool ctrlPressed = RawKeyboard.instance.keysPressed
.contains(LogicalKeyboardKey.controlLeft);
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) {

View File

@ -3,6 +3,8 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'paint_controller.dart';
import 'path/path_transform.dart';
import 'path/ring_number_provider.dart';
import 'screen_document_mapping.dart';
final Rect a4Page =
@ -81,18 +83,37 @@ 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);
}
// active pen hover effects
switch (activePen) {
case 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);
}
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;
}
}

View File

@ -18,6 +18,7 @@ class PaintController extends ChangeNotifier {
Offset? _currentPointerPosition;
Pen activePen = Pen.pen;
List<Stroke> strokes = [];
Offset? _selectionStart;
PaintController(this.file);
@ -37,38 +38,59 @@ class PaintController extends ChangeNotifier {
// todo line drawn on edge where line left page
if (!a4Page.contains(offset)) return;
// todo handle other pens
if (activePen == Pen.eraser || activePen == Pen.selector) return;
int strokeid = strokes.isNotEmpty ? strokes.last.id + 1 : 0;
final color = activePen == Pen.pen
? const Color(0xFF444444)
: Colors.yellow.withOpacity(.3);
strokes.add(Stroke.fromPoints(
[Point(offset, _calcTiltedWidth(3.0, e.tilt))], strokeid, color));
file.addStroke(strokeid, color);
notifyListeners();
switch (activePen) {
case Pen.pen:
case Pen.highlighter:
int strokeid = strokes.isNotEmpty ? strokes.last.id + 1 : 0;
final color = activePen == Pen.pen
? const Color(0xFF444444)
: Colors.yellow.withOpacity(.3);
strokes.add(Stroke.fromPoints(
[Point(offset, _calcTiltedWidth(3.0, e.tilt))], strokeid, color));
file.addStroke(strokeid, color);
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) {
_currentPointerPosition = null;
notifyListeners();
if (activePen == Pen.eraser) return;
// pointerupevent doesn't deliver correct event button
if (_allowedToDraw(e.kind, 1)) {
final lastStroke = strokes.last;
if (lastStroke.points.length <= 1) {
// if the line consists only of one point (point) add endpoint as the same to allow drawing a line
lastStroke.points.add(lastStroke.points.last);
file.addPoint(lastStroke.id, lastStroke.points.last);
notifyListeners();
} else {
debugPrint('adding points to db');
file.addPoints(lastStroke.id, lastStroke.points);
}
switch (activePen) {
case Pen.pen:
case Pen.highlighter:
// pointerupevent doesn't deliver correct event button
if (_allowedToDraw(e.kind, 1)) {
final lastStroke = strokes.last;
if (lastStroke.points.length <= 1) {
// if the line consists only of one point (point) add endpoint as the same to allow drawing a line
lastStroke.points.add(lastStroke.points.last);
file.addPoint(lastStroke.id, lastStroke.points.last);
notifyListeners();
} else {
debugPrint('adding points to db');
file.addPoints(lastStroke.id, lastStroke.points);
}
}
break;
case Pen.selector:
_selectionStart = null;
// todo highlight current selection
break;
default:
break;
}
}

View 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;
}
}

View 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++];
}
}