Skip to content

Commit 23b7381

Browse files
committed
(PR) feat: allows scaling eraser with display and shows a dotted
circumference around it saber-notes#1639 Signed-off-by: AnErrupTion <anerruption@disroot.org>
1 parent d5a2881 commit 23b7381

File tree

5 files changed

+79
-4
lines changed

5 files changed

+79
-4
lines changed

lib/components/canvas/_canvas_painter.dart

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class CanvasPainter extends CustomPainter {
5555
_drawCurrentStroke(canvas);
5656
_drawDetectedShape(canvas);
5757
_drawSelection(canvas);
58+
_drawEraserIndicator(canvas);
5859
_drawPageIndicator(canvas, size);
5960
}
6061

@@ -74,7 +75,8 @@ class CanvasPainter extends CustomPainter {
7475
showPageIndicator != oldDelegate.showPageIndicator ||
7576
pageIndex != oldDelegate.pageIndex ||
7677
totalPages != oldDelegate.totalPages ||
77-
currentScale != oldDelegate.currentScale;
78+
currentScale != oldDelegate.currentScale ||
79+
page.eraserPosition != oldDelegate.page.eraserPosition;
7880
}
7981

8082
void _drawHighlighterStrokes(Canvas canvas, Rect canvasRect) {
@@ -250,6 +252,25 @@ class CanvasPainter extends CustomPainter {
250252
);
251253
}
252254

255+
void _drawEraserIndicator(Canvas canvas) {
256+
if (page.eraserPosition == null) return;
257+
final radius = 10.0 / currentScale; // Eraser().size is 10 by default
258+
259+
final path = Path()
260+
..addOval(Rect.fromCircle(center: page.eraserPosition!, radius: radius));
261+
262+
canvas.drawPath(
263+
dashPath(
264+
path,
265+
dashArray: CircularIntervalList([5 / currentScale, 5 / currentScale]),
266+
),
267+
Paint()
268+
..color = Colors.grey
269+
..strokeWidth = 1.0 / currentScale
270+
..style = PaintingStyle.stroke,
271+
);
272+
}
273+
253274
static const double _pageIndicatorFontSize = 20;
254275
static const double _pageIndicatorPadding = 5;
255276
void _drawPageIndicator(Canvas canvas, Size pageSize) {

lib/data/editor/page.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class EditorPage extends ChangeNotifier implements HasSize {
2828
@override
2929
final Size size;
3030

31+
Offset? eraserPosition;
32+
3133
late final CanvasKey innerCanvasKey = CanvasKey();
3234
RenderBox? _renderBox;
3335
RenderBox? get renderBox {

lib/data/tools/eraser.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ class Eraser extends Tool {
2222
/// Returns any [strokes] that are close to the given [eraserPos].
2323
List<Stroke> checkForOverlappingStrokes(
2424
Offset eraserPos,
25-
List<Stroke> strokes,
26-
) {
25+
List<Stroke> strokes, {
26+
double scale = 1.0,
27+
}) {
28+
final effectiveSqrSize = sqrSize / square(scale);
2729
final List<Stroke> overlapping = [];
2830
for (int i = 0; i < strokes.length; i++) {
2931
final stroke = strokes[i];
30-
if (_shouldStrokeBeErased(eraserPos, stroke, sqrSize)) {
32+
if (_shouldStrokeBeErased(eraserPos, stroke, effectiveSqrSize)) {
3133
overlapping.add(stroke);
3234
_erased.add(stroke);
3335
}

lib/pages/editor/editor.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,9 +564,11 @@ class EditorState extends State<Editor> {
564564
currentPressure,
565565
);
566566
} else if (currentTool is Eraser) {
567+
page.eraserPosition = position;
567568
for (final stroke in (currentTool as Eraser).checkForOverlappingStrokes(
568569
position,
569570
page.strokes,
571+
scale: _transformationController.value.approxScale,
570572
)) {
571573
page.strokes.remove(stroke);
572574
}
@@ -605,9 +607,11 @@ class EditorState extends State<Editor> {
605607
(currentTool as Pen).onDragUpdate(position, currentPressure);
606608
page.redrawStrokes();
607609
} else if (currentTool is Eraser) {
610+
page.eraserPosition = position;
608611
for (final stroke in (currentTool as Eraser).checkForOverlappingStrokes(
609612
position,
610613
page.strokes,
614+
scale: _transformationController.value.approxScale,
611615
)) {
612616
page.strokes.remove(stroke);
613617
}
@@ -661,6 +665,7 @@ class EditorState extends State<Editor> {
661665
),
662666
);
663667
} else if (currentTool is Eraser) {
668+
page.eraserPosition = null;
664669
final erased = (currentTool as Eraser).onDragEnd();
665670
if (tmpTool != null &&
666671
(stylusButtonPressed || stows.disableEraserAfterUse.value)) {

test/tools_eraser_test.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,51 @@ void main() {
8686
reason: 'The correct strokes should have been erased',
8787
);
8888
});
89+
90+
test('Test that eraser size scales inversely with zoom', () {
91+
final eraser = Eraser(size: 10);
92+
// At scale 1.0, this stroke is at the edge (distance = size)
93+
// At scale 2.0, the effective size should be 5, so this stroke (at 10) should NOT be erased
94+
final strokeAtEdge = _strokeWithPoint(
95+
_eraserPos + const Offset(1, 0) * eraser.size,
96+
);
97+
98+
// Check with scale 1.0 (default)
99+
var erased = eraser.checkForOverlappingStrokes(_eraserPos, [
100+
strokeAtEdge,
101+
], scale: 1.0);
102+
expect(
103+
erased.contains(strokeAtEdge),
104+
true,
105+
reason: 'Should erase stroke at edge with scale 1.0',
106+
);
107+
108+
// Check with scale 2.0 (eraser should be smaller in document coordinates)
109+
erased = eraser.checkForOverlappingStrokes(_eraserPos, [
110+
strokeAtEdge,
111+
], scale: 2.0);
112+
expect(
113+
erased.contains(strokeAtEdge),
114+
false,
115+
reason:
116+
'Should NOT erase stroke at distance 10 when scale is 2.0 (effective size 5)',
117+
);
118+
119+
// At scale 0.5, effective size should be 20.
120+
// A stroke at distance 15 should be erased.
121+
final strokeFurtherAway = _strokeWithPoint(
122+
_eraserPos + const Offset(1.5, 0) * eraser.size,
123+
);
124+
erased = eraser.checkForOverlappingStrokes(_eraserPos, [
125+
strokeFurtherAway,
126+
], scale: 0.5);
127+
expect(
128+
erased.contains(strokeFurtherAway),
129+
true,
130+
reason:
131+
'Should erase stroke at distance 15 when scale is 0.5 (effective size 20)',
132+
);
133+
});
89134
}
90135

91136
Stroke _strokeWithPoint(Offset point) => Stroke(

0 commit comments

Comments
 (0)