// lib/editor/render/annotation_layer.dart // // Composites the static committed-stroke layer and the live in-progress layer // into a single widget. Wrap the page widget with this to get ink rendering. // // Layout: // RepaintBoundary // └─ Stack // ├─ CustomPaint(StaticInkPainter) ← repaints only on revision bump // └─ CustomPaint(LiveInkPainter) ← repaints on every pointer move import 'package:flutter/material.dart'; import '../engine/stroke_model.dart'; import '../engine/stroke_store.dart'; import 'ink_picture_cache.dart'; import 'live_ink_painter.dart'; import 'static_ink_painter.dart'; /// A [StatelessWidget] that renders committed and live ink strokes over a /// [pageSize]-sized area. /// /// Place it as an overlay on top of the page content; it is fully transparent /// where no strokes are drawn. /// /// [hostId] identifies the ink host (e.g. page id) and is used as the cache /// key prefix so multiple pages can share an [InkPictureCache] instance. class AnnotationLayer extends StatelessWidget { const AnnotationLayer({ super.key, required this.hostId, required this.store, required this.liveStroke, required this.pageSize, required this.cache, }); final String hostId; final StrokeStore store; /// The stroke currently being drawn, or null when idle. final EditorStroke? liveStroke; final Size pageSize; final InkPictureCache cache; @override Widget build(BuildContext context) { return RepaintBoundary( child: Stack( children: [ CustomPaint( size: pageSize, painter: StaticInkPainter( hostId: hostId, store: store, pageSize: pageSize, cache: cache, ), ), CustomPaint( size: pageSize, painter: LiveInkPainter( live: liveStroke, pageSize: pageSize, ), ), ], ), ); } }