David PHAM-VAN

Add Page.orientation to force landscape or portrait

1 # 1.3.4 1 # 1.3.4
2 * Add available dimensions for PdfPageFormat 2 * Add available dimensions for PdfPageFormat
3 * Add Document properties 3 * Add Document properties
  4 +* Add Page.orientation to force landscape or portrait
4 5
5 # 1.3.3 6 # 1.3.3
6 * Fix a bug with the RichText Widget 7 * Fix a bug with the RichText Widget
@@ -16,15 +16,6 @@ @@ -16,15 +16,6 @@
16 16
17 part of widget; 17 part of widget;
18 18
19 -abstract class BasePage {  
20 - BasePage({@required this.pageFormat}) : assert(pageFormat != null);  
21 -  
22 - final PdfPageFormat pageFormat;  
23 -  
24 - @protected  
25 - void generate(Document document);  
26 -}  
27 -  
28 class Document { 19 class Document {
29 Document( 20 Document(
30 {PdfPageMode pageMode = PdfPageMode.none, 21 {PdfPageMode pageMode = PdfPageMode.none,
@@ -52,7 +43,7 @@ class Document { @@ -52,7 +43,7 @@ class Document {
52 43
53 final Theme theme; 44 final Theme theme;
54 45
55 - void addPage(BasePage page) { 46 + void addPage(Page page) {
56 page.generate(this); 47 page.generate(this);
57 } 48 }
58 49
@@ -62,44 +53,83 @@ class Document { @@ -62,44 +53,83 @@ class Document {
62 typedef BuildCallback = Widget Function(Context context); 53 typedef BuildCallback = Widget Function(Context context);
63 typedef BuildListCallback = List<Widget> Function(Context context); 54 typedef BuildListCallback = List<Widget> Function(Context context);
64 55
65 -class Page extends BasePage {  
66 - Page(  
67 - {PdfPageFormat pageFormat = PdfPageFormat.standard, 56 +enum PageOrientation { natural, landscape, portrait }
  57 +
  58 +class Page {
  59 + const Page(
  60 + {this.pageFormat = PdfPageFormat.standard,
68 BuildCallback build, 61 BuildCallback build,
69 this.theme, 62 this.theme,
  63 + this.orientation = PageOrientation.natural,
70 EdgeInsets margin}) 64 EdgeInsets margin})
71 - : margin = margin ??  
72 - EdgeInsets.fromLTRB(pageFormat.marginLeft, pageFormat.marginTop,  
73 - pageFormat.marginRight, pageFormat.marginBottom),  
74 - _build = build,  
75 - super(pageFormat: pageFormat); 65 + : assert(pageFormat != null),
  66 + _margin = margin,
  67 + _build = build;
  68 +
  69 + final PdfPageFormat pageFormat;
  70 +
  71 + final PageOrientation orientation;
76 72
77 - final EdgeInsets margin; 73 + final EdgeInsets _margin;
78 74
79 final BuildCallback _build; 75 final BuildCallback _build;
80 76
81 final Theme theme; 77 final Theme theme;
82 78
  79 + bool get mustRotate =>
  80 + (orientation == PageOrientation.landscape &&
  81 + pageFormat.height > pageFormat.width) ||
  82 + (orientation == PageOrientation.portrait &&
  83 + pageFormat.width > pageFormat.height);
  84 +
  85 + EdgeInsets get margin {
  86 + if (_margin != null) {
  87 + if (mustRotate) {
  88 + return EdgeInsets.fromLTRB(
  89 + _margin.bottom, _margin.left, _margin.top, _margin.right);
  90 + } else {
  91 + return _margin;
  92 + }
  93 + }
  94 +
  95 + if (mustRotate) {
  96 + return EdgeInsets.fromLTRB(pageFormat.marginBottom, pageFormat.marginLeft,
  97 + pageFormat.marginTop, pageFormat.marginRight);
  98 + } else {
  99 + return EdgeInsets.fromLTRB(pageFormat.marginLeft, pageFormat.marginTop,
  100 + pageFormat.marginRight, pageFormat.marginBottom);
  101 + }
  102 + }
  103 +
  104 + @protected
83 void debugPaint(Context context) { 105 void debugPaint(Context context) {
  106 + final EdgeInsets _margin = margin;
84 context.canvas 107 context.canvas
85 ..setFillColor(PdfColor.lightGreen) 108 ..setFillColor(PdfColor.lightGreen)
86 ..moveTo(0, 0) 109 ..moveTo(0, 0)
87 ..lineTo(pageFormat.width, 0) 110 ..lineTo(pageFormat.width, 0)
88 ..lineTo(pageFormat.width, pageFormat.height) 111 ..lineTo(pageFormat.width, pageFormat.height)
89 ..lineTo(0, pageFormat.height) 112 ..lineTo(0, pageFormat.height)
90 - ..moveTo(margin.left, margin.bottom)  
91 - ..lineTo(margin.left, pageFormat.height - margin.top)  
92 - ..lineTo(pageFormat.width - margin.right, pageFormat.height - margin.top)  
93 - ..lineTo(pageFormat.width - margin.right, margin.bottom) 113 + ..moveTo(_margin.left, _margin.bottom)
  114 + ..lineTo(_margin.left, pageFormat.height - _margin.top)
  115 + ..lineTo(
  116 + pageFormat.width - _margin.right, pageFormat.height - _margin.top)
  117 + ..lineTo(pageFormat.width - _margin.right, _margin.bottom)
94 ..fillPath(); 118 ..fillPath();
95 } 119 }
96 120
97 - @override 121 + @protected
98 void generate(Document document) { 122 void generate(Document document) {
99 final PdfPage pdfPage = PdfPage(document.document, pageFormat: pageFormat); 123 final PdfPage pdfPage = PdfPage(document.document, pageFormat: pageFormat);
100 final PdfGraphics canvas = pdfPage.getGraphics(); 124 final PdfGraphics canvas = pdfPage.getGraphics();
101 - final BoxConstraints constraints = BoxConstraints(  
102 - maxWidth: pageFormat.width, maxHeight: pageFormat.height); 125 + final EdgeInsets _margin = margin;
  126 + final BoxConstraints constraints = mustRotate
  127 + ? BoxConstraints(
  128 + maxWidth: pageFormat.height - _margin.vertical,
  129 + maxHeight: pageFormat.width - _margin.horizontal)
  130 + : BoxConstraints(
  131 + maxWidth: pageFormat.width - _margin.horizontal,
  132 + maxHeight: pageFormat.height - _margin.vertical);
103 133
104 final Theme calculatedTheme = theme ?? document.theme ?? Theme.base(); 134 final Theme calculatedTheme = theme ?? document.theme ?? Theme.base();
105 final Map<Type, Inherited> inherited = <Type, Inherited>{}; 135 final Map<Type, Inherited> inherited = <Type, Inherited>{};
@@ -120,19 +150,11 @@ class Page extends BasePage { @@ -120,19 +150,11 @@ class Page extends BasePage {
120 void layout(Widget child, Context context, BoxConstraints constraints, 150 void layout(Widget child, Context context, BoxConstraints constraints,
121 {bool parentUsesSize = false}) { 151 {bool parentUsesSize = false}) {
122 if (child != null) { 152 if (child != null) {
123 - final BoxConstraints childConstraints = BoxConstraints(  
124 - minWidth: constraints.minWidth,  
125 - minHeight: constraints.minHeight,  
126 - maxWidth: constraints.hasBoundedWidth  
127 - ? constraints.maxWidth - margin.horizontal  
128 - : margin.horizontal,  
129 - maxHeight: constraints.hasBoundedHeight  
130 - ? constraints.maxHeight - margin.vertical  
131 - : margin.vertical);  
132 - child.layout(context, childConstraints, parentUsesSize: parentUsesSize); 153 + final EdgeInsets _margin = margin;
  154 + child.layout(context, constraints, parentUsesSize: parentUsesSize);
133 child.box = PdfRect( 155 child.box = PdfRect(
134 - margin.left,  
135 - pageFormat.height - child.box.height - margin.top, 156 + _margin.left,
  157 + pageFormat.height - child.box.height - _margin.top,
136 child.box.width, 158 child.box.width,
137 child.box.height); 159 child.box.height);
138 } 160 }
@@ -147,23 +169,44 @@ class Page extends BasePage { @@ -147,23 +169,44 @@ class Page extends BasePage {
147 return true; 169 return true;
148 }()); 170 }());
149 171
150 - if (child != null) { 172 + if (child == null) {
  173 + return;
  174 + }
  175 +
  176 + if (mustRotate) {
  177 + final EdgeInsets _margin = margin;
  178 + final Matrix4 mat = Matrix4.identity();
  179 + mat
  180 + ..rotateZ(-math.pi / 2)
  181 + ..translate(-pageFormat.height - _margin.left + _margin.top,
  182 + child.box.height - child.box.width + _margin.left - _margin.bottom);
  183 + context.canvas
  184 + ..saveContext()
  185 + ..setTransform(mat);
  186 + child.paint(context);
  187 + context.canvas.restoreContext();
  188 + } else {
151 child.paint(context); 189 child.paint(context);
152 } 190 }
153 } 191 }
154 } 192 }
155 193
156 class MultiPage extends Page { 194 class MultiPage extends Page {
157 - MultiPage( 195 + const MultiPage(
158 {PdfPageFormat pageFormat = PdfPageFormat.a4, 196 {PdfPageFormat pageFormat = PdfPageFormat.a4,
159 BuildListCallback build, 197 BuildListCallback build,
160 this.crossAxisAlignment = CrossAxisAlignment.start, 198 this.crossAxisAlignment = CrossAxisAlignment.start,
161 this.header, 199 this.header,
162 this.footer, 200 this.footer,
163 Theme theme, 201 Theme theme,
  202 + PageOrientation orientation = PageOrientation.natural,
164 EdgeInsets margin}) 203 EdgeInsets margin})
165 : _buildList = build, 204 : _buildList = build,
166 - super(pageFormat: pageFormat, margin: margin, theme: theme); 205 + super(
  206 + pageFormat: pageFormat,
  207 + margin: margin,
  208 + theme: theme,
  209 + orientation: orientation);
167 210
168 final BuildListCallback _buildList; 211 final BuildListCallback _buildList;
169 212
@@ -173,16 +216,40 @@ class MultiPage extends Page { @@ -173,16 +216,40 @@ class MultiPage extends Page {
173 216
174 final BuildCallback footer; 217 final BuildCallback footer;
175 218
  219 + void paintChild(
  220 + Context context, Widget child, double x, double y, double pageHeight) {
  221 + if (mustRotate) {
  222 + final EdgeInsets _margin = margin;
  223 + context.canvas
  224 + ..saveContext()
  225 + ..setTransform(Matrix4.identity()
  226 + ..rotateZ(-math.pi / 2)
  227 + ..translate(x - pageHeight + _margin.top - _margin.left,
  228 + y + _margin.left - _margin.bottom));
  229 + child.paint(context);
  230 + context.canvas.restoreContext();
  231 + } else {
  232 + child.box = PdfRect(x, y, child.box.width, child.box.height);
  233 + child.paint(context);
  234 + }
  235 + }
  236 +
176 @override 237 @override
177 void generate(Document document) { 238 void generate(Document document) {
178 if (_buildList == null) { 239 if (_buildList == null) {
179 return; 240 return;
180 } 241 }
181 242
  243 + final EdgeInsets _margin = margin;
  244 + final bool _mustRotate = mustRotate;
  245 + final double pageHeight =
  246 + _mustRotate ? pageFormat.width : pageFormat.height;
  247 + final double pageHeightMargin =
  248 + _mustRotate ? _margin.horizontal : _margin.vertical;
182 final BoxConstraints constraints = BoxConstraints( 249 final BoxConstraints constraints = BoxConstraints(
183 - maxWidth: pageFormat.width, maxHeight: pageFormat.height);  
184 - final BoxConstraints childConstraints =  
185 - BoxConstraints(maxWidth: constraints.maxWidth - margin.horizontal); 250 + maxWidth: _mustRotate
  251 + ? (pageFormat.height - _margin.vertical)
  252 + : (pageFormat.width - _margin.horizontal));
186 final Theme calculatedTheme = theme ?? document.theme ?? Theme.base(); 253 final Theme calculatedTheme = theme ?? document.theme ?? Theme.base();
187 final Map<Type, Inherited> inherited = <Type, Inherited>{}; 254 final Map<Type, Inherited> inherited = <Type, Inherited>{};
188 inherited[calculatedTheme.runtimeType] = calculatedTheme; 255 inherited[calculatedTheme.runtimeType] = calculatedTheme;
@@ -209,19 +276,16 @@ class MultiPage extends Page { @@ -209,19 +276,16 @@ class MultiPage extends Page {
209 } 276 }
210 return true; 277 return true;
211 }()); 278 }());
212 - offsetStart = pageFormat.height - margin.top;  
213 - offsetEnd = margin.bottom; 279 + offsetStart = pageHeight -
  280 + (_mustRotate ? pageHeightMargin - margin.bottom : _margin.top);
  281 + offsetEnd =
  282 + _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom;
214 if (header != null) { 283 if (header != null) {
215 final Widget headerWidget = header(context); 284 final Widget headerWidget = header(context);
216 if (headerWidget != null) { 285 if (headerWidget != null) {
217 - headerWidget.layout(context, childConstraints,  
218 - parentUsesSize: false);  
219 - headerWidget.box = PdfRect(  
220 - margin.left,  
221 - offsetStart - headerWidget.box.height,  
222 - headerWidget.box.width,  
223 - headerWidget.box.height);  
224 - headerWidget.paint(context); 286 + headerWidget.layout(context, constraints, parentUsesSize: false);
  287 + paintChild(context, headerWidget, _margin.left,
  288 + offsetStart - headerWidget.box.height, pageFormat.height);
225 offsetStart -= headerWidget.box.height; 289 offsetStart -= headerWidget.box.height;
226 } 290 }
227 } 291 }
@@ -229,11 +293,9 @@ class MultiPage extends Page { @@ -229,11 +293,9 @@ class MultiPage extends Page {
229 if (footer != null) { 293 if (footer != null) {
230 final Widget footerWidget = footer(context); 294 final Widget footerWidget = footer(context);
231 if (footerWidget != null) { 295 if (footerWidget != null) {
232 - footerWidget.layout(context, childConstraints,  
233 - parentUsesSize: false);  
234 - footerWidget.box = PdfRect(margin.left, margin.bottom,  
235 - footerWidget.box.width, footerWidget.box.height);  
236 - footerWidget.paint(context); 296 + footerWidget.layout(context, constraints, parentUsesSize: false);
  297 + paintChild(context, footerWidget, _margin.left, _margin.bottom,
  298 + pageFormat.height);
237 offsetEnd += footerWidget.box.height; 299 offsetEnd += footerWidget.box.height;
238 } 300 }
239 } 301 }
@@ -244,10 +306,11 @@ class MultiPage extends Page { @@ -244,10 +306,11 @@ class MultiPage extends Page {
244 widgetContext = null; 306 widgetContext = null;
245 } 307 }
246 308
247 - child.layout(context, childConstraints, parentUsesSize: false); 309 + child.layout(context, constraints, parentUsesSize: false);
248 310
249 if (offsetStart - child.box.height < offsetEnd) { 311 if (offsetStart - child.box.height < offsetEnd) {
250 - if (child.box.height <= pageFormat.height - margin.vertical) { 312 + if (child.box.height <= pageHeight - pageHeightMargin &&
  313 + !(child is SpanningWidget)) {
251 context = null; 314 context = null;
252 continue; 315 continue;
253 } 316 }
@@ -255,18 +318,17 @@ class MultiPage extends Page { @@ -255,18 +318,17 @@ class MultiPage extends Page {
255 if (!(child is SpanningWidget)) { 318 if (!(child is SpanningWidget)) {
256 throw Exception( 319 throw Exception(
257 'Widget won\'t fit into the page as its height (${child.box.height}) ' 320 'Widget won\'t fit into the page as its height (${child.box.height}) '
258 - 'exceed a page height (${pageFormat.height - margin.vertical}). ' 321 + 'exceed a page height (${pageHeight - pageHeightMargin}). '
259 'You probably need a SpanningWidget or use a single page layout'); 322 'You probably need a SpanningWidget or use a single page layout');
260 } 323 }
261 324
262 final SpanningWidget span = child; 325 final SpanningWidget span = child;
263 326
264 - child.layout(context,  
265 - childConstraints.copyWith(maxHeight: offsetStart - offsetEnd), 327 + child.layout(
  328 + context, constraints.copyWith(maxHeight: offsetStart - offsetEnd),
266 parentUsesSize: false); 329 parentUsesSize: false);
267 - child.box = PdfRect(margin.left, offsetStart - child.box.height,  
268 - child.box.width, child.box.height);  
269 - child.paint(context); 330 + paintChild(context, child, _margin.left, offsetStart - child.box.height,
  331 + pageFormat.height);
270 332
271 if (span.canSpan) { 333 if (span.canSpan) {
272 widgetContext = span.saveContext(); 334 widgetContext = span.saveContext();
@@ -278,9 +340,8 @@ class MultiPage extends Page { @@ -278,9 +340,8 @@ class MultiPage extends Page {
278 continue; 340 continue;
279 } 341 }
280 342
281 - child.box = PdfRect(margin.left, offsetStart - child.box.height,  
282 - child.box.width, child.box.height);  
283 - child.paint(context); 343 + paintChild(context, child, _margin.left, offsetStart - child.box.height,
  344 + pageFormat.height);
284 offsetStart -= child.box.height; 345 offsetStart -= child.box.height;
285 index++; 346 index++;
286 } 347 }
@@ -266,6 +266,9 @@ class EdgeInsets { @@ -266,6 +266,9 @@ class EdgeInsets {
266 bottom + other.bottom, 266 bottom + other.bottom,
267 ); 267 );
268 } 268 }
  269 +
  270 + @override
  271 + String toString() => 'EdgeInsets $left, $top, $right, $bottom';
269 } 272 }
270 273
271 class Alignment { 274 class Alignment {