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/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++];
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user