Files
BadNote/lib/editor/canvas/pen_stroke.dart
T

62 lines
2.1 KiB
Dart
Raw Normal View History

2026-06-21 22:04:49 +08:00
// 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';
2026-06-21 22:04:49 +08:00
/// 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.
2026-06-21 22:04:49 +08:00
@immutable
class PenPoint {
const PenPoint(this.x, this.y, this.pressure, {this.tilt});
2026-06-21 22:04:49 +08:00
final double x;
final double y;
final double? pressure;
final double? tilt;
2026-06-21 22:04:49 +08:00
}
/// 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,
2026-06-21 22:04:49 +08:00
});
/// Normalized points (see [PenPoint]).
final List<PenPoint> 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;
2026-06-21 22:04:49 +08:00
}