feat(f3): viewport fit/centering math (fit-width / fit-page / center)
Some checks failed
CI / Windows build (push) Has been cancelled
Some checks failed
CI / Windows build (push) Has been cancelled
Extracts the untested ad-hoc arithmetic from pen_editor_screen._centerPage into pure, shared, tested functions: fitWidthScale (fill viewport width — the continuous-single default), fitPageScale (letterboxed min-axis fit), and centerOffset (top-left translation to center scaled content; negative when it overflows/scrolls). Powers the viewport's initial transform + the reader fit-width/fit-page actions. flutter analyze lib/editor clean; 228/228 tests (+5). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
39
lib/editor/layout/viewport_fit.dart
Normal file
39
lib/editor/layout/viewport_fit.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
// lib/editor/layout/viewport_fit.dart
|
||||
//
|
||||
// Pure fit/centering math for the viewport's initial transform + the reader
|
||||
// "fit width / fit page" actions (F3). Today this lives as untested ad-hoc
|
||||
// arithmetic in pen_editor_screen._centerPage; extracting it here makes it
|
||||
// testable and shared by the new viewport widget.
|
||||
//
|
||||
// Content coordinates are scale-1 logical px; the returned scale + offset place
|
||||
// content inside the viewport. No widgets beyond dart:ui Size/Offset.
|
||||
|
||||
import 'dart:ui' show Offset, Size;
|
||||
|
||||
/// Scale so content width fills the viewport width (fit-to-width, the
|
||||
/// continuous-single default). 0 for non-positive content width.
|
||||
double fitWidthScale(Size content, double viewportWidth) {
|
||||
if (content.width <= 0) return 0;
|
||||
return viewportWidth / content.width;
|
||||
}
|
||||
|
||||
/// Scale so the whole content fits inside the viewport (letterboxed) —
|
||||
/// min(widthFit, heightFit). 0 for non-positive content extents.
|
||||
double fitPageScale(Size content, Size viewport) {
|
||||
if (content.width <= 0 || content.height <= 0) return 0;
|
||||
final w = viewport.width / content.width;
|
||||
final h = viewport.height / content.height;
|
||||
return w < h ? w : h;
|
||||
}
|
||||
|
||||
/// Top-left translation that centers [content] scaled by [scale] within
|
||||
/// [viewport]. When the scaled content is larger than the viewport on an axis
|
||||
/// the offset is negative (content overflows equally on both sides).
|
||||
Offset centerOffset(Size content, Size viewport, double scale) {
|
||||
final scaledW = content.width * scale;
|
||||
final scaledH = content.height * scale;
|
||||
return Offset(
|
||||
(viewport.width - scaledW) / 2.0,
|
||||
(viewport.height - scaledH) / 2.0,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user