Showing
7 changed files
with
213 additions
and
34 deletions
| @@ -37,6 +37,7 @@ part 'widgets/grid_view.dart'; | @@ -37,6 +37,7 @@ part 'widgets/grid_view.dart'; | ||
| 37 | part 'widgets/image.dart'; | 37 | part 'widgets/image.dart'; |
| 38 | part 'widgets/multi_page.dart'; | 38 | part 'widgets/multi_page.dart'; |
| 39 | part 'widgets/page.dart'; | 39 | part 'widgets/page.dart'; |
| 40 | +part 'widgets/page_theme.dart'; | ||
| 40 | part 'widgets/placeholders.dart'; | 41 | part 'widgets/placeholders.dart'; |
| 41 | part 'widgets/progress.dart'; | 42 | part 'widgets/progress.dart'; |
| 42 | part 'widgets/stack.dart'; | 43 | part 'widgets/stack.dart'; |
| @@ -40,27 +40,31 @@ class _MultiPageInstance { | @@ -40,27 +40,31 @@ class _MultiPageInstance { | ||
| 40 | const _MultiPageInstance( | 40 | const _MultiPageInstance( |
| 41 | {@required this.context, | 41 | {@required this.context, |
| 42 | @required this.constraints, | 42 | @required this.constraints, |
| 43 | + @required this.fullConstraints, | ||
| 43 | @required this.offsetStart}); | 44 | @required this.offsetStart}); |
| 44 | 45 | ||
| 45 | final Context context; | 46 | final Context context; |
| 46 | final BoxConstraints constraints; | 47 | final BoxConstraints constraints; |
| 48 | + final BoxConstraints fullConstraints; | ||
| 47 | final double offsetStart; | 49 | final double offsetStart; |
| 48 | } | 50 | } |
| 49 | 51 | ||
| 50 | class MultiPage extends Page { | 52 | class MultiPage extends Page { |
| 51 | MultiPage( | 53 | MultiPage( |
| 52 | - {PdfPageFormat pageFormat = PdfPageFormat.a4, | 54 | + {PageTheme pageTheme, |
| 55 | + PdfPageFormat pageFormat, | ||
| 53 | BuildListCallback build, | 56 | BuildListCallback build, |
| 54 | this.crossAxisAlignment = CrossAxisAlignment.start, | 57 | this.crossAxisAlignment = CrossAxisAlignment.start, |
| 55 | this.header, | 58 | this.header, |
| 56 | this.footer, | 59 | this.footer, |
| 57 | Theme theme, | 60 | Theme theme, |
| 58 | this.maxPages = 20, | 61 | this.maxPages = 20, |
| 59 | - PageOrientation orientation = PageOrientation.natural, | 62 | + PageOrientation orientation, |
| 60 | EdgeInsets margin}) | 63 | EdgeInsets margin}) |
| 61 | : _buildList = build, | 64 | : _buildList = build, |
| 62 | assert(maxPages != null && maxPages > 0), | 65 | assert(maxPages != null && maxPages > 0), |
| 63 | super( | 66 | super( |
| 67 | + pageTheme: pageTheme, | ||
| 64 | pageFormat: pageFormat, | 68 | pageFormat: pageFormat, |
| 65 | margin: margin, | 69 | margin: margin, |
| 66 | theme: theme, | 70 | theme: theme, |
| @@ -88,6 +92,7 @@ class MultiPage extends Page { | @@ -88,6 +92,7 @@ class MultiPage extends Page { | ||
| 88 | ..rotateZ(-math.pi / 2) | 92 | ..rotateZ(-math.pi / 2) |
| 89 | ..translate(x - pageHeight + _margin.top - _margin.left, | 93 | ..translate(x - pageHeight + _margin.top - _margin.left, |
| 90 | y + _margin.left - _margin.bottom)); | 94 | y + _margin.left - _margin.bottom)); |
| 95 | + | ||
| 91 | child.paint(context); | 96 | child.paint(context); |
| 92 | context.canvas.restoreContext(); | 97 | context.canvas.restoreContext(); |
| 93 | } else { | 98 | } else { |
| @@ -112,6 +117,13 @@ class MultiPage extends Page { | @@ -112,6 +117,13 @@ class MultiPage extends Page { | ||
| 112 | maxWidth: _mustRotate | 117 | maxWidth: _mustRotate |
| 113 | ? (pageFormat.height - _margin.vertical) | 118 | ? (pageFormat.height - _margin.vertical) |
| 114 | : (pageFormat.width - _margin.horizontal)); | 119 | : (pageFormat.width - _margin.horizontal)); |
| 120 | + final BoxConstraints fullConstraints = mustRotate | ||
| 121 | + ? BoxConstraints( | ||
| 122 | + maxWidth: pageFormat.height - _margin.vertical, | ||
| 123 | + maxHeight: pageFormat.width - _margin.horizontal) | ||
| 124 | + : BoxConstraints( | ||
| 125 | + maxWidth: pageFormat.width - _margin.horizontal, | ||
| 126 | + maxHeight: pageFormat.height - _margin.vertical); | ||
| 115 | final Theme calculatedTheme = theme ?? document.theme ?? Theme.base(); | 127 | final Theme calculatedTheme = theme ?? document.theme ?? Theme.base(); |
| 116 | Context context; | 128 | Context context; |
| 117 | double offsetEnd; | 129 | double offsetEnd; |
| @@ -149,6 +161,16 @@ class MultiPage extends Page { | @@ -149,6 +161,16 @@ class MultiPage extends Page { | ||
| 149 | return true; | 161 | return true; |
| 150 | }()); | 162 | }()); |
| 151 | 163 | ||
| 164 | + if (pageTheme.buildBackground != null) { | ||
| 165 | + final Widget child = pageTheme.buildBackground(context); | ||
| 166 | + if (child != null) { | ||
| 167 | + child.layout(context, fullConstraints, parentUsesSize: false); | ||
| 168 | + assert(child.box != null); | ||
| 169 | + _paintChild(context, child, _margin.left, _margin.bottom, | ||
| 170 | + pageFormat.height); | ||
| 171 | + } | ||
| 172 | + } | ||
| 173 | + | ||
| 152 | offsetStart = pageHeight - | 174 | offsetStart = pageHeight - |
| 153 | (_mustRotate ? pageHeightMargin - margin.bottom : _margin.top); | 175 | (_mustRotate ? pageHeightMargin - margin.bottom : _margin.top); |
| 154 | offsetEnd = | 176 | offsetEnd = |
| @@ -157,6 +179,7 @@ class MultiPage extends Page { | @@ -157,6 +179,7 @@ class MultiPage extends Page { | ||
| 157 | _pages.add(_MultiPageInstance( | 179 | _pages.add(_MultiPageInstance( |
| 158 | context: context, | 180 | context: context, |
| 159 | constraints: constraints, | 181 | constraints: constraints, |
| 182 | + fullConstraints: fullConstraints, | ||
| 160 | offsetStart: offsetStart, | 183 | offsetStart: offsetStart, |
| 161 | )); | 184 | )); |
| 162 | 185 | ||
| @@ -262,6 +285,17 @@ class MultiPage extends Page { | @@ -262,6 +285,17 @@ class MultiPage extends Page { | ||
| 262 | pageFormat.height); | 285 | pageFormat.height); |
| 263 | } | 286 | } |
| 264 | } | 287 | } |
| 288 | + | ||
| 289 | + if (pageTheme.buildForeground != null) { | ||
| 290 | + final Widget child = pageTheme.buildForeground(page.context); | ||
| 291 | + if (child != null) { | ||
| 292 | + child.layout(page.context, page.fullConstraints, | ||
| 293 | + parentUsesSize: false); | ||
| 294 | + assert(child.box != null); | ||
| 295 | + _paintChild(page.context, child, _margin.left, _margin.bottom, | ||
| 296 | + pageFormat.height); | ||
| 297 | + } | ||
| 298 | + } | ||
| 265 | } | 299 | } |
| 266 | } | 300 | } |
| 267 | } | 301 | } |
| @@ -23,51 +23,43 @@ enum PageOrientation { natural, landscape, portrait } | @@ -23,51 +23,43 @@ enum PageOrientation { natural, landscape, portrait } | ||
| 23 | 23 | ||
| 24 | class Page { | 24 | class Page { |
| 25 | Page( | 25 | Page( |
| 26 | - {this.pageFormat = PdfPageFormat.standard, | 26 | + {PageTheme pageTheme, |
| 27 | + PdfPageFormat pageFormat, | ||
| 27 | BuildCallback build, | 28 | BuildCallback build, |
| 28 | - this.theme, | ||
| 29 | - this.orientation = PageOrientation.natural, | 29 | + Theme theme, |
| 30 | + PageOrientation orientation, | ||
| 30 | EdgeInsets margin}) | 31 | EdgeInsets margin}) |
| 31 | - : assert(pageFormat != null), | ||
| 32 | - _margin = margin, | 32 | + : assert( |
| 33 | + pageTheme == null || | ||
| 34 | + (pageFormat == null && | ||
| 35 | + theme == null && | ||
| 36 | + orientation == null && | ||
| 37 | + margin == null), | ||
| 38 | + 'Don\'t set both pageTheme and other settings'), | ||
| 39 | + pageTheme = pageTheme ?? | ||
| 40 | + PageTheme( | ||
| 41 | + pageFormat: pageFormat, | ||
| 42 | + orientation: orientation, | ||
| 43 | + margin: margin, | ||
| 44 | + theme: theme, | ||
| 45 | + ), | ||
| 33 | _build = build; | 46 | _build = build; |
| 34 | 47 | ||
| 35 | - final PdfPageFormat pageFormat; | 48 | + final PageTheme pageTheme; |
| 36 | 49 | ||
| 37 | - final PageOrientation orientation; | 50 | + PdfPageFormat get pageFormat => pageTheme.pageFormat; |
| 38 | 51 | ||
| 39 | - final EdgeInsets _margin; | 52 | + PageOrientation get orientation => pageTheme.orientation; |
| 40 | 53 | ||
| 41 | final BuildCallback _build; | 54 | final BuildCallback _build; |
| 42 | 55 | ||
| 43 | - final Theme theme; | 56 | + Theme get theme => pageTheme.theme; |
| 44 | 57 | ||
| 45 | - bool get mustRotate => | ||
| 46 | - (orientation == PageOrientation.landscape && | ||
| 47 | - pageFormat.height > pageFormat.width) || | ||
| 48 | - (orientation == PageOrientation.portrait && | ||
| 49 | - pageFormat.width > pageFormat.height); | 58 | + bool get mustRotate => pageTheme.mustRotate; |
| 50 | 59 | ||
| 51 | PdfPage _pdfPage; | 60 | PdfPage _pdfPage; |
| 52 | 61 | ||
| 53 | - EdgeInsets get margin { | ||
| 54 | - if (_margin != null) { | ||
| 55 | - if (mustRotate) { | ||
| 56 | - return EdgeInsets.fromLTRB( | ||
| 57 | - _margin.bottom, _margin.left, _margin.top, _margin.right); | ||
| 58 | - } else { | ||
| 59 | - return _margin; | ||
| 60 | - } | ||
| 61 | - } | ||
| 62 | - | ||
| 63 | - if (mustRotate) { | ||
| 64 | - return EdgeInsets.fromLTRB(pageFormat.marginBottom, pageFormat.marginLeft, | ||
| 65 | - pageFormat.marginTop, pageFormat.marginRight); | ||
| 66 | - } else { | ||
| 67 | - return EdgeInsets.fromLTRB(pageFormat.marginLeft, pageFormat.marginTop, | ||
| 68 | - pageFormat.marginRight, pageFormat.marginBottom); | ||
| 69 | - } | ||
| 70 | - } | 62 | + EdgeInsets get margin => pageTheme.margin; |
| 71 | 63 | ||
| 72 | @protected | 64 | @protected |
| 73 | void debugPaint(Context context) { | 65 | void debugPaint(Context context) { |
| @@ -109,12 +101,28 @@ class Page { | @@ -109,12 +101,28 @@ class Page { | ||
| 109 | page: _pdfPage, | 101 | page: _pdfPage, |
| 110 | canvas: canvas, | 102 | canvas: canvas, |
| 111 | ).inheritFrom(calculatedTheme); | 103 | ).inheritFrom(calculatedTheme); |
| 104 | + if (pageTheme.buildBackground != null) { | ||
| 105 | + final Widget child = pageTheme.buildBackground(context); | ||
| 106 | + if (child != null) { | ||
| 107 | + layout(child, context, constraints); | ||
| 108 | + paint(child, context); | ||
| 109 | + } | ||
| 110 | + } | ||
| 112 | if (_build != null) { | 111 | if (_build != null) { |
| 113 | final Widget child = _build(context); | 112 | final Widget child = _build(context); |
| 113 | + if (child != null) { | ||
| 114 | + layout(child, context, constraints); | ||
| 115 | + paint(child, context); | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + if (pageTheme.buildForeground != null) { | ||
| 119 | + final Widget child = pageTheme.buildForeground(context); | ||
| 120 | + if (child != null) { | ||
| 114 | layout(child, context, constraints); | 121 | layout(child, context, constraints); |
| 115 | paint(child, context); | 122 | paint(child, context); |
| 116 | } | 123 | } |
| 117 | } | 124 | } |
| 125 | + } | ||
| 118 | 126 | ||
| 119 | @protected | 127 | @protected |
| 120 | void layout(Widget child, Context context, BoxConstraints constraints, | 128 | void layout(Widget child, Context context, BoxConstraints constraints, |
pdf/lib/widgets/page_theme.dart
0 → 100644
| 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 | +part of widget; | ||
| 18 | + | ||
| 19 | +@immutable | ||
| 20 | +class PageTheme { | ||
| 21 | + const PageTheme( | ||
| 22 | + {PdfPageFormat pageFormat, | ||
| 23 | + this.buildBackground, | ||
| 24 | + this.buildForeground, | ||
| 25 | + this.theme, | ||
| 26 | + PageOrientation orientation, | ||
| 27 | + EdgeInsets margin}) | ||
| 28 | + : pageFormat = pageFormat ?? PdfPageFormat.standard, | ||
| 29 | + orientation = orientation ?? PageOrientation.natural, | ||
| 30 | + _margin = margin; | ||
| 31 | + | ||
| 32 | + final PdfPageFormat pageFormat; | ||
| 33 | + | ||
| 34 | + final PageOrientation orientation; | ||
| 35 | + | ||
| 36 | + final EdgeInsets _margin; | ||
| 37 | + | ||
| 38 | + final BuildCallback buildBackground; | ||
| 39 | + | ||
| 40 | + final BuildCallback buildForeground; | ||
| 41 | + | ||
| 42 | + final Theme theme; | ||
| 43 | + | ||
| 44 | + bool get mustRotate => | ||
| 45 | + (orientation == PageOrientation.landscape && | ||
| 46 | + pageFormat.height > pageFormat.width) || | ||
| 47 | + (orientation == PageOrientation.portrait && | ||
| 48 | + pageFormat.width > pageFormat.height); | ||
| 49 | + | ||
| 50 | + EdgeInsets get margin { | ||
| 51 | + if (_margin != null) { | ||
| 52 | + if (mustRotate) { | ||
| 53 | + return EdgeInsets.fromLTRB( | ||
| 54 | + _margin.bottom, _margin.left, _margin.top, _margin.right); | ||
| 55 | + } else { | ||
| 56 | + return _margin; | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + if (mustRotate) { | ||
| 61 | + return EdgeInsets.fromLTRB(pageFormat.marginBottom, pageFormat.marginLeft, | ||
| 62 | + pageFormat.marginTop, pageFormat.marginRight); | ||
| 63 | + } else { | ||
| 64 | + return EdgeInsets.fromLTRB(pageFormat.marginLeft, pageFormat.marginTop, | ||
| 65 | + pageFormat.marginRight, pageFormat.marginBottom); | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | +} |
| @@ -34,6 +34,7 @@ import 'widget_table_test.dart' as widget_table; | @@ -34,6 +34,7 @@ import 'widget_table_test.dart' as widget_table; | ||
| 34 | import 'widget_test.dart' as widget; | 34 | import 'widget_test.dart' as widget; |
| 35 | import 'widget_text_test.dart' as widget_text; | 35 | import 'widget_text_test.dart' as widget_text; |
| 36 | import 'widget_theme_test.dart' as widget_theme; | 36 | import 'widget_theme_test.dart' as widget_theme; |
| 37 | +import 'widget_watermark_test.dart' as widget_watermark; | ||
| 37 | import 'widget_wrap_test.dart' as widget_wrap; | 38 | import 'widget_wrap_test.dart' as widget_wrap; |
| 38 | 39 | ||
| 39 | void main() { | 40 | void main() { |
| @@ -54,6 +55,7 @@ void main() { | @@ -54,6 +55,7 @@ void main() { | ||
| 54 | widget_table.main(); | 55 | widget_table.main(); |
| 55 | widget_text.main(); | 56 | widget_text.main(); |
| 56 | widget_theme.main(); | 57 | widget_theme.main(); |
| 58 | + widget_watermark.main(); | ||
| 57 | widget_wrap.main(); | 59 | widget_wrap.main(); |
| 58 | widget.main(); | 60 | widget.main(); |
| 59 | } | 61 | } |
pdf/test/widget_watermark_test.dart
0 → 100644
| 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/widgets.dart'; | ||
| 20 | +import 'package:test/test.dart'; | ||
| 21 | + | ||
| 22 | +void main() { | ||
| 23 | + test('Pdf Widgets Watermark', () { | ||
| 24 | + Document.debug = true; | ||
| 25 | + final Document pdf = Document(); | ||
| 26 | + | ||
| 27 | + final PageTheme pageTheme = PageTheme( | ||
| 28 | + buildBackground: (Context context) => Watermark.text('DRAFT'), | ||
| 29 | + buildForeground: (Context context) => Align( | ||
| 30 | + alignment: Alignment.bottomLeft, | ||
| 31 | + child: SizedBox( | ||
| 32 | + width: 100, | ||
| 33 | + height: 100, | ||
| 34 | + child: PdfLogo(), | ||
| 35 | + ), | ||
| 36 | + ), | ||
| 37 | + ); | ||
| 38 | + | ||
| 39 | + pdf.addPage( | ||
| 40 | + Page( | ||
| 41 | + pageTheme: pageTheme, | ||
| 42 | + build: (Context context) => Center( | ||
| 43 | + child: Text( | ||
| 44 | + 'Hello World', | ||
| 45 | + ), | ||
| 46 | + ), | ||
| 47 | + ), | ||
| 48 | + ); | ||
| 49 | + | ||
| 50 | + pdf.addPage( | ||
| 51 | + MultiPage( | ||
| 52 | + pageTheme: pageTheme, | ||
| 53 | + build: (Context context) => List<Widget>.filled( | ||
| 54 | + 100, | ||
| 55 | + Text( | ||
| 56 | + 'Hello World', | ||
| 57 | + ), | ||
| 58 | + ), | ||
| 59 | + ), | ||
| 60 | + ); | ||
| 61 | + | ||
| 62 | + final File file = File('widgets-watermark.pdf'); | ||
| 63 | + file.writeAsBytesSync(pdf.save()); | ||
| 64 | + }); | ||
| 65 | +} |
-
Please register or login to post a comment