Stefan (von Windows)
Committed by David PHAM-VAN

NewPage with freeSpace extended

@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 ## 3.11.0 3 ## 3.11.0
4 4
5 - Save in an isolate when available 5 - Save in an isolate when available
  6 +- NewPage with freeSpace extended [Stefan]
6 7
7 ## 3.10.8 8 ## 3.10.8
8 9
@@ -65,12 +65,20 @@ mixin SpanningWidget on Widget { @@ -65,12 +65,20 @@ mixin SpanningWidget on Widget {
65 saveContext().apply(context); 65 saveContext().apply(context);
66 } 66 }
67 67
  68 +/// Trigger a page break if there is not enough free space.
  69 +/// If freeSpace is null, a page break is always performed.
68 class NewPage extends Widget { 70 class NewPage extends Widget {
  71 + NewPage({this.freeSpace});
  72 + final double? freeSpace;
  73 +
69 @override 74 @override
70 void layout(Context context, BoxConstraints constraints, 75 void layout(Context context, BoxConstraints constraints,
71 {bool parentUsesSize = false}) { 76 {bool parentUsesSize = false}) {
72 box = PdfRect.zero; 77 box = PdfRect.zero;
73 } 78 }
  79 +
  80 + bool newPageNeeded(double availableSpace) =>
  81 + (freeSpace == null) || (availableSpace < freeSpace!);
74 } 82 }
75 83
76 @immutable 84 @immutable
@@ -230,7 +238,7 @@ class MultiPage extends Page { @@ -230,7 +238,7 @@ class MultiPage extends Page {
230 maxHeight: pageFormat.height - _margin.vertical); 238 maxHeight: pageFormat.height - _margin.vertical);
231 final calculatedTheme = theme ?? document.theme ?? ThemeData.base(); 239 final calculatedTheme = theme ?? document.theme ?? ThemeData.base();
232 Context? context; 240 Context? context;
233 - late double offsetEnd; 241 + var offsetEnd = 0.0;
234 double? offsetStart; 242 double? offsetStart;
235 var _index = 0; 243 var _index = 0;
236 var sameCount = 0; 244 var sameCount = 0;
@@ -252,8 +260,14 @@ class MultiPage extends Page { @@ -252,8 +260,14 @@ class MultiPage extends Page {
252 'This widget created more than $maxPages pages. This may be an issue in the widget or the document. See https://pub.dev/documentation/pdf/latest/widgets/MultiPage-class.html'); 260 'This widget created more than $maxPages pages. This may be an issue in the widget or the document. See https://pub.dev/documentation/pdf/latest/widgets/MultiPage-class.html');
253 } 261 }
254 262
  263 + // Calculate available space of the current page
  264 + final freeSpace = (offsetStart == null)
  265 + ? fullConstraints.maxHeight
  266 + : offsetStart - offsetEnd;
  267 +
255 // Create a new page if we don't already have one 268 // Create a new page if we don't already have one
256 - if (context == null || child is NewPage) { 269 + if (context == null ||
  270 + (child is NewPage) && child.newPageNeeded(freeSpace)) {
257 final pdfPage = PdfPage( 271 final pdfPage = PdfPage(
258 document.document, 272 document.document,
259 pageFormat: pageFormat, 273 pageFormat: pageFormat,
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +import 'dart:io';
  18 +
  19 +import 'package:pdf/pdf.dart';
  20 +import 'package:pdf/widgets.dart';
  21 +import 'package:test/test.dart';
  22 +
  23 +late Document pdf;
  24 +
  25 +Widget footer(Context context) {
  26 + return Footer(
  27 + trailing: Container(
  28 + height: 25,
  29 + child: Text('Page ${context.pageNumber}'),
  30 + ),
  31 + );
  32 +}
  33 +
  34 +Widget header(Context context) {
  35 + return Container(
  36 + height: 20,
  37 + child: Text('Test document'),
  38 + );
  39 +}
  40 +
  41 +List<Widget> contentWithPageBreak(double? freeSpace) {
  42 + return [
  43 + Container(
  44 + color: const PdfColor(0.75, 0.75, 0.75),
  45 + height: 50,
  46 + width: 100,
  47 + child: Text('Page 1'),
  48 + ),
  49 + Container(
  50 + color: const PdfColor(0.6, 0.6, 0.6),
  51 + height: 40,
  52 + width: 100,
  53 + ),
  54 + Container(
  55 + color: const PdfColor(0.5, 0.5, 0.5),
  56 + height: 20,
  57 + width: 100,
  58 + ),
  59 + NewPage(freeSpace: freeSpace),
  60 + Text('Page 2'),
  61 + ];
  62 +}
  63 +
  64 +void main() {
  65 + setUpAll(() {
  66 + Document.debug = true;
  67 + RichText.debug = true;
  68 + pdf = Document();
  69 + });
  70 +
  71 + const pageFormatWithoutMargins = PdfPageFormat(200.0, 200.0);
  72 + const pageFormatWithMargins =
  73 + PdfPageFormat(200.0, 200.0, marginTop: 10, marginBottom: 20);
  74 +
  75 + // PageHeight - Content Height
  76 + // 200 - 110 = 90 available space
  77 + test('PageBreak normal on page without margins', () {
  78 + pdf.addPage(MultiPage(
  79 + pageFormat: pageFormatWithoutMargins,
  80 + build: (_) => contentWithPageBreak(null),
  81 + ));
  82 + });
  83 +
  84 + test('No PageBreak, because enough space available', () {
  85 + pdf.addPage(MultiPage(
  86 + pageFormat: pageFormatWithoutMargins,
  87 + build: (_) => contentWithPageBreak(90),
  88 + ));
  89 + });
  90 +
  91 + test('PageBreak because more free space needed', () {
  92 + pdf.addPage(MultiPage(
  93 + pageFormat: pageFormatWithoutMargins,
  94 + build: (_) => contentWithPageBreak(91),
  95 + ));
  96 + });
  97 +
  98 + // PageHeight - Margins - Content Height
  99 + // 200 - 10 - 20 - 20 - 25 - 110 = 15
  100 + test('PageBreak normal on page with margins, header and footer', () {
  101 + pdf.addPage(MultiPage(
  102 + pageFormat: pageFormatWithMargins,
  103 + build: (_) => contentWithPageBreak(null),
  104 + header: header,
  105 + footer: footer,
  106 + ));
  107 + });
  108 +
  109 + test('No PageBreak, because enough space available', () {
  110 + pdf.addPage(MultiPage(
  111 + pageFormat: pageFormatWithMargins,
  112 + build: (_) => contentWithPageBreak(15.0),
  113 + header: header,
  114 + footer: footer,
  115 + ));
  116 + });
  117 +
  118 + test('PageBreak because more free space needed', () {
  119 + pdf.addPage(MultiPage(
  120 + pageFormat: pageFormatWithMargins,
  121 + build: (_) => contentWithPageBreak(16.0),
  122 + header: header,
  123 + footer: footer,
  124 + ));
  125 + });
  126 +
  127 + tearDownAll(() async {
  128 + final file = File('widgets-newpage.pdf');
  129 + await file.writeAsBytes(await pdf.save());
  130 + });
  131 +}
No preview for this file type