allow zooming on desktop when holding ctrl and scrolling
add prototype of selection mode, span up dashed rectangle
This commit is contained in:
parent
4899381510
commit
8e0cd05ded
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
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++];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user