outline active eraser pen when erasing

info text when no note is available
This commit is contained in:
lukas-heiligenbrunner 2022-11-17 12:06:53 +01:00
parent 6d3d74ebc7
commit ce1d081e16
3 changed files with 126 additions and 73 deletions

View File

@ -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 @override

View File

@ -12,45 +12,24 @@ import 'my_painter.dart';
enum Pen { eraser, pen, highlighter, selector } enum Pen { eraser, pen, highlighter, selector }
class PaintController extends ChangeNotifier { class PaintController extends ChangeNotifier {
final bool _allowDrawWithFinger = false;
final NoteFile file;
Offset? _currentPointerPosition;
Pen activePen = Pen.pen; Pen activePen = Pen.pen;
List<Stroke> strokes = []; List<Stroke> strokes = [];
final bool _allowDrawWithFinger = false;
PaintController(this.file); PaintController(this.file);
final NoteFile file;
void changePen(Pen pen) { void changePen(Pen pen) {
activePen = pen; activePen = pen;
notifyListeners(); notifyListeners();
} }
double _calcTiltedWidth(double baseWidth, double tilt) { /// return current position of pointer
if (tilt == .0) return baseWidth; /// null if nowhere hovering or painting
return baseWidth * tilt; Offset? getPointerPosition() {
} return _currentPointerPosition;
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;
} }
void pointDownEvent(Offset offset, PointerDownEvent e) async { void pointDownEvent(Offset offset, PointerDownEvent e) async {
@ -73,6 +52,9 @@ class PaintController extends ChangeNotifier {
} }
void pointUpEvent(PointerUpEvent e) { void pointUpEvent(PointerUpEvent e) {
_currentPointerPosition = null;
notifyListeners();
if (activePen == Pen.eraser) return; if (activePen == Pen.eraser) return;
// pointerupevent doesn't deliver correct event button // 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) { void pointMoveEvent(Offset offset, PointerMoveEvent event) {
_currentPointerPosition = offset;
if (!a4Page.contains(offset)) { if (!a4Page.contains(offset)) {
return; return;
} }
@ -106,10 +83,10 @@ class PaintController extends ChangeNotifier {
switch (activePen) { switch (activePen) {
case Pen.eraser: case Pen.eraser:
// todo dynamic eraser size // 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) { for (final stroke in strokes) {
// check if delete action was within bounding rect of stroke // 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 // check if eraser hit an point within its range
for (final pt in stroke.points) { for (final pt in stroke.points) {
if (eraserrect.contains(pt.point)) { if (eraserrect.contains(pt.point)) {
@ -155,4 +132,39 @@ class PaintController extends ChangeNotifier {
debugPrint('finished loading strokes from file'); debugPrint('finished loading strokes from file');
notifyListeners(); 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;
}
} }

View File

@ -209,48 +209,75 @@ class _AllNotesPageState extends State<AllNotesPage> {
Widget _buildNoteTiles() { Widget _buildNoteTiles() {
return Consumer<FileChangeNotifier>( return Consumer<FileChangeNotifier>(
builder: (BuildContext context, value, Widget? child) { builder: (BuildContext context, value, Widget? child) {
return Expanded( if (value.tiledata.isEmpty) {
child: GridView.builder( return _buildNoNotesText();
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( } else {
crossAxisCount: 6, childAspectRatio: 0.7), return Expanded(
physics: const ScrollPhysics(), child: GridView.builder(
padding: const EdgeInsets.all(2), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
itemBuilder: (BuildContext context, int idx) => NoteTile( crossAxisCount: 6, childAspectRatio: 0.7),
data: value.tiledata[idx], physics: const ScrollPhysics(),
selectionMode: selectionMode, padding: const EdgeInsets.all(2),
selected: selectionIdx.contains(idx), itemBuilder: (BuildContext context, int idx) => NoteTile(
onSelectionChange: (selection) { data: value.tiledata[idx],
if (selection) { selectionMode: selectionMode,
if (!selectionMode) { selected: selectionIdx.contains(idx),
setState(() { onSelectionChange: (selection) {
selectionMode = true; if (selection) {
}); if (!selectionMode) {
} setState(() {
if (!selectionIdx.contains(idx)) { selectionMode = true;
});
}
if (!selectionIdx.contains(idx)) {
final sel = selectionIdx;
sel.add(idx);
setState(() {
selectionIdx = sel;
});
}
} else {
final sel = selectionIdx; final sel = selectionIdx;
sel.add(idx); sel.remove(idx);
if (sel.isEmpty) {
setState(() {
selectionMode = false;
});
}
setState(() { setState(() {
selectionIdx = sel; selectionIdx = sel;
}); });
} }
} else { },
final sel = selectionIdx; ),
sel.remove(idx); itemCount: value.tiledata.length,
if (sel.isEmpty) {
setState(() {
selectionMode = false;
});
}
setState(() {
selectionIdx = sel;
});
}
},
), ),
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),
)
],
),
);
}
} }