diff --git a/test/pen_coordinate_widget_test.dart b/test/pen_coordinate_widget_test.dart new file mode 100644 index 0000000..ebeba46 --- /dev/null +++ b/test/pen_coordinate_widget_test.dart @@ -0,0 +1,58 @@ +// Device-independent correctness guard: a drawn point must map to the right +// NORMALIZED page coordinate through a non-identity (zoomed) transform, so ink +// stays glued to the page under zoom/pan. + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:badnote/editor/canvas/pen_canvas.dart'; +import 'package:badnote/editor/canvas/pen_stroke.dart'; + +void main() { + const pageSize = Size(400, 600); + + testWidgets('a stylus point maps to correct normalized coords at 2x zoom', + (tester) async { + final committed = []; + final controller = TransformationController() + ..value = (Matrix4.identity()..scaleByDouble(2.0, 2.0, 2.0, 1)); + addTearDown(controller.dispose); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Center( + child: SizedBox( + width: pageSize.width, + height: pageSize.height, + child: PenCanvas( + pageWidget: Container(color: const Color(0xFFEEEEEE)), + pageSize: pageSize, + strokes: const [], + transformationController: controller, + tool: CanvasTool.pen, + color: const Color(0xFF000000), + strokeWidth: 0.004, + onStrokeComplete: committed.add, + onEraseStroke: (_, __) {}, + ), + ), + ), + ), + )); + + // Down at the canvas-local point (200, 300). At 2x scale, scene = (100,150), + // normalized = (100/400, 150/600) = (0.25, 0.25). + final topLeft = tester.getTopLeft(find.byType(PenCanvas)); + final g = await tester.startGesture(topLeft + const Offset(200, 300), + kind: PointerDeviceKind.stylus); + await g.moveBy(const Offset(8, 8)); // make it a stroke, not a tap + await g.up(); + await tester.pump(); + + expect(committed, hasLength(1)); + final first = committed.single.points.first; + expect(first.x, closeTo(0.25, 1e-3)); + expect(first.y, closeTo(0.25, 1e-3)); + }); +}