import 'package:flutter/material.dart'; import 'drawing_controller.dart'; import 'drawing_line.dart'; /// Custom painter that renders drawing lines on a canvas. /// /// Converts normalized coordinates (0-1) to actual canvas coordinates /// based on the provided canvas size. class DrawingPainter extends CustomPainter { final List lines; final DrawingLine? currentLine; final Size canvasSize; DrawingPainter({ required this.lines, required this.currentLine, required this.canvasSize, }); @override void paint(Canvas canvas, Size size) { // Draw all completed lines for (final line in lines) { _drawLine(canvas, line); } // Draw the current line being drawn if (currentLine != null) { _drawLine(canvas, currentLine!); } } void _drawLine(Canvas canvas, DrawingLine line) { if (line.points.length < 2) return; final paint = Paint() ..color = line.color ..strokeWidth = line.strokeWidth * canvasSize.width ..strokeCap = StrokeCap.round ..strokeJoin = StrokeJoin.round ..style = PaintingStyle.stroke ..isAntiAlias = true; // Create path from normalized points final path = Path(); final firstPoint = _toCanvasPoint(line.points.first); path.moveTo(firstPoint.dx, firstPoint.dy); // Use quadratic bezier curves for smooth lines if (line.points.length == 2) { final endPoint = _toCanvasPoint(line.points.last); path.lineTo(endPoint.dx, endPoint.dy); } else { for (int i = 1; i < line.points.length - 1; i++) { final p0 = _toCanvasPoint(line.points[i]); final p1 = _toCanvasPoint(line.points[i + 1]); final midPoint = Offset((p0.dx + p1.dx) / 2, (p0.dy + p1.dy) / 2); path.quadraticBezierTo(p0.dx, p0.dy, midPoint.dx, midPoint.dy); } // Draw to the last point final lastPoint = _toCanvasPoint(line.points.last); path.lineTo(lastPoint.dx, lastPoint.dy); } canvas.drawPath(path, paint); } /// Converts a normalized point (0-1) to canvas coordinates. Offset _toCanvasPoint(Offset normalizedPoint) { return Offset( normalizedPoint.dx * canvasSize.width, normalizedPoint.dy * canvasSize.height, ); } @override bool shouldRepaint(covariant DrawingPainter oldDelegate) { return lines != oldDelegate.lines || currentLine != oldDelegate.currentLine || canvasSize != oldDelegate.canvasSize; } } /// A widget that displays drawing lines on a transparent canvas. /// /// This widget only shows the drawings, it doesn't handle input. /// Use [DrawingCanvas] or [DrawingBoard] for input handling. class DrawingOverlay extends StatelessWidget { final DrawingController controller; final Size canvasSize; const DrawingOverlay({ super.key, required this.controller, required this.canvasSize, }); @override Widget build(BuildContext context) { return ListenableBuilder( listenable: controller, builder: (context, _) { return CustomPaint( size: canvasSize, painter: DrawingPainter( lines: controller.lines, currentLine: controller.currentLine, canvasSize: canvasSize, ), ); }, ); } }