Showing
3 changed files
with
135 additions
and
70 deletions
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 { |
-
Please register or login to post a comment