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