// lib/editor/canvas/pen_stroke.dart // // Pen-first canvas stroke model. Points are stored in NORMALIZED page // coordinates ([0,1] x [0,1] relative to the page rectangle) so strokes stay // pinned to the page regardless of zoom/pan or the on-screen page size. import 'package:flutter/foundation.dart'; import '../engine/brush.dart'; /// A single captured sample of a stroke. /// /// [x]/[y] are normalized to the page rectangle ([0,1]). /// [pressure] is the normalized stylus pressure ([0,1]) or null when the /// device reported no usable pressure (perfect_freehand then simulates it). /// [tilt] is the pen tilt magnitude in degrees (0 = perpendicular), or null /// when unavailable. On Windows it is sourced from the native pen plugin /// (`badnote/pen`) since Flutter 3.44 does not surface tilt itself. @immutable class PenPoint { const PenPoint(this.x, this.y, this.pressure, {this.tilt}); final double x; final double y; final double? pressure; final double? tilt; } /// Which kind of mark a stroke is. enum PenStrokeKind { pen, highlighter } /// A committed stroke for a single page, in normalized page coordinates. @immutable class PenStroke { const PenStroke({ required this.points, required this.color, required this.width, required this.kind, this.brush = BrushKind.fountainPen, }); /// Normalized points (see [PenPoint]). final List points; /// ARGB color value. final int color; /// Stroke width expressed as a fraction of the page width, so it scales with /// the page when zoomed. Multiply by the on-screen page width to get pixels. final double width; final PenStrokeKind kind; /// The brush this stroke was drawn with — drives the perfect_freehand /// geometry (thinning/streamline/smoothing/caps) at render time via /// [brushProfileFor]. The pressure pre-warp ([BrushProfile.pressureGamma]) is /// applied at CAPTURE so it is already baked into [points]. Defaults to /// [BrushKind.fountainPen] (the legacy pen visual) so old/loaded strokes keep /// rendering as before. final BrushKind brush; }