fix(canvas): persist strokes, pressure, slider
All checks were successful
CI / Windows build (push) Successful in 8m33s

Strokes vanished on pen-up: StaticInkPainter aliased the same mutable
list so shouldRepaint saw no change. Commit/erase now replace the list.
Finger-drawing toggle wins over palm-rejection; pressure surfaces even
when the pen reports no min/max range; pages recenter after a flip; the
keyboard page-jump (unreliable on Windows) is now a drag slider. Also
register the dynamic_color plugin in generated registrants.
This commit is contained in:
2026-06-21 22:33:18 +08:00
parent 3febbd1431
commit 0c40a456e8
7 changed files with 109 additions and 76 deletions

View File

@@ -93,16 +93,15 @@ class _PenCanvasState extends State<PenCanvas> {
/// Live stroke snapshot handed to the LiveInkPainter; null when idle.
PenStroke? _liveStroke;
/// True once any stylus event is seen this session → finger-drawing forced
/// off so a resting palm pans instead of marking.
bool _stylusSeen = false;
/// True when the active stylus reports the eraser signal (barrel button or
/// inverted stylus), detected on hover/down.
bool _eraserActive = false;
bool get _fingerDrawingEnabled =>
widget.allowFingerDrawing && !_stylusSeen;
// The explicit user toggle wins: if finger-drawing is ON, a single finger
// draws even after a stylus has been seen. (Palm rejection when the toggle is
// OFF is automatic — fingers simply never draw — and a 2nd pointer always
// cancels an in-progress stroke regardless.)
bool get _fingerDrawingEnabled => widget.allowFingerDrawing;
bool _isStylus(PointerDeviceKind kind) =>
kind == PointerDeviceKind.stylus ||
@@ -112,9 +111,17 @@ class _PenCanvasState extends State<PenCanvas> {
/// usable pressure range (then perfect_freehand simulates pressure).
double? _normalizedPressure(PointerEvent event) {
if (!_isStylus(event.kind)) return null;
if (event.pressureMin == event.pressureMax) return null;
final range = event.pressureMax - event.pressureMin;
return ((event.pressure - event.pressureMin) / range).clamp(0.0, 1.0);
if (range > 0.0001) {
return ((event.pressure - event.pressureMin) / range).clamp(0.0, 1.0);
}
// No advertised range (some Windows pen stacks): use the raw normalized
// pressure directly if it's a usable non-degenerate value, so we still get
// real force instead of falling back to velocity simulation.
if (event.pressure > 0.0 && event.pressure < 1.0) {
return event.pressure;
}
return null;
}
/// The eraser signal: barrel/secondary button held, or an inverted stylus.
@@ -244,7 +251,6 @@ class _PenCanvasState extends State<PenCanvas> {
void _onPointerHover(PointerHoverEvent event) {
if (_isStylus(event.kind)) {
_stylusSeen = true;
// Detect eraser (barrel button / inverted) while hovering.
_eraserActive = _isEraserSignal(event);
}
@@ -252,7 +258,6 @@ class _PenCanvasState extends State<PenCanvas> {
void _onPointerDown(PointerDownEvent event) {
if (event.kind == PointerDeviceKind.trackpad) return;
if (_isStylus(event.kind)) _stylusSeen = true;
_activePointers[event.pointer] = event.kind;