Showing
20 changed files
with
650 additions
and
404 deletions
| @@ -122,12 +122,13 @@ class Calendar extends StatelessWidget { | @@ -122,12 +122,13 @@ class Calendar extends StatelessWidget { | ||
| 122 | return Expanded( | 122 | return Expanded( |
| 123 | child: Container( | 123 | child: Container( |
| 124 | foregroundDecoration: BoxDecoration( | 124 | foregroundDecoration: BoxDecoration( |
| 125 | - border: BoxBorder( | ||
| 126 | - color: PdfColors.grey, | ||
| 127 | - top: true, | ||
| 128 | - left: true, | ||
| 129 | - right: index % 7 == 6, | ||
| 130 | - bottom: true, | 125 | + border: Border( |
| 126 | + top: const BorderSide(color: PdfColors.grey), | ||
| 127 | + left: const BorderSide(color: PdfColors.grey), | ||
| 128 | + right: index % 7 == 6 | ||
| 129 | + ? const BorderSide(color: PdfColors.grey) | ||
| 130 | + : BorderSide.none, | ||
| 131 | + bottom: const BorderSide(color: PdfColors.grey), | ||
| 131 | ), | 132 | ), |
| 132 | ), | 133 | ), |
| 133 | child: header(context, d), | 134 | child: header(context, d), |
| @@ -146,13 +147,13 @@ class Calendar extends StatelessWidget { | @@ -146,13 +147,13 @@ class Calendar extends StatelessWidget { | ||
| 146 | d.day == _date.day; | 147 | d.day == _date.day; |
| 147 | return Container( | 148 | return Container( |
| 148 | foregroundDecoration: BoxDecoration( | 149 | foregroundDecoration: BoxDecoration( |
| 149 | - border: BoxBorder( | ||
| 150 | - color: PdfColors.grey, | ||
| 151 | - left: true, | ||
| 152 | - right: index % 7 == 6, | ||
| 153 | - bottom: true, | ||
| 154 | - ), | ||
| 155 | - ), | 150 | + border: Border( |
| 151 | + left: const BorderSide(color: PdfColors.grey), | ||
| 152 | + right: index % 7 == 6 | ||
| 153 | + ? const BorderSide(color: PdfColors.grey) | ||
| 154 | + : BorderSide.none, | ||
| 155 | + bottom: const BorderSide(color: PdfColors.grey), | ||
| 156 | + )), | ||
| 156 | child: day(context, d, currentMonth, currentDay), | 157 | child: day(context, d, currentMonth, currentDay), |
| 157 | ); | 158 | ); |
| 158 | }), | 159 | }), |
| @@ -35,8 +35,8 @@ Future<Uint8List> generateDocument(PdfPageFormat format) async { | @@ -35,8 +35,8 @@ Future<Uint8List> generateDocument(PdfPageFormat format) async { | ||
| 35 | margin: const pw.EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm), | 35 | margin: const pw.EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm), |
| 36 | padding: const pw.EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm), | 36 | padding: const pw.EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm), |
| 37 | decoration: const pw.BoxDecoration( | 37 | decoration: const pw.BoxDecoration( |
| 38 | - border: pw.BoxBorder( | ||
| 39 | - bottom: true, width: 0.5, color: PdfColors.grey)), | 38 | + border: pw.Border( |
| 39 | + bottom: pw.BorderSide(width: 0.5, color: PdfColors.grey))), | ||
| 40 | child: pw.Text('Portable Document Format', | 40 | child: pw.Text('Portable Document Format', |
| 41 | style: pw.Theme.of(context) | 41 | style: pw.Theme.of(context) |
| 42 | .defaultTextStyle | 42 | .defaultTextStyle |
| @@ -449,10 +449,7 @@ class Invoice { | @@ -449,10 +449,7 @@ class Invoice { | ||
| 449 | children: [ | 449 | children: [ |
| 450 | pw.Container( | 450 | pw.Container( |
| 451 | decoration: pw.BoxDecoration( | 451 | decoration: pw.BoxDecoration( |
| 452 | - border: pw.BoxBorder( | ||
| 453 | - top: true, | ||
| 454 | - color: accentColor, | ||
| 455 | - ), | 452 | + border: pw.Border(top: pw.BorderSide(color: accentColor)), |
| 456 | ), | 453 | ), |
| 457 | padding: const pw.EdgeInsets.only(top: 10, bottom: 4), | 454 | padding: const pw.EdgeInsets.only(top: 10, bottom: 4), |
| 458 | child: pw.Text( | 455 | child: pw.Text( |
| @@ -518,10 +515,11 @@ class Invoice { | @@ -518,10 +515,11 @@ class Invoice { | ||
| 518 | fontSize: 10, | 515 | fontSize: 10, |
| 519 | ), | 516 | ), |
| 520 | rowDecoration: pw.BoxDecoration( | 517 | rowDecoration: pw.BoxDecoration( |
| 521 | - border: pw.BoxBorder( | ||
| 522 | - bottom: true, | ||
| 523 | - color: accentColor, | ||
| 524 | - width: .5, | 518 | + border: pw.Border( |
| 519 | + bottom: pw.BorderSide( | ||
| 520 | + color: accentColor, | ||
| 521 | + width: .5, | ||
| 522 | + ), | ||
| 525 | ), | 523 | ), |
| 526 | ), | 524 | ), |
| 527 | headers: List<String>.generate( | 525 | headers: List<String>.generate( |
| @@ -150,10 +150,11 @@ Future<Uint8List> generateReport(PdfPageFormat pageFormat) async { | @@ -150,10 +150,11 @@ Future<Uint8List> generateReport(PdfPageFormat pageFormat) async { | ||
| 150 | color: baseColor, | 150 | color: baseColor, |
| 151 | ), | 151 | ), |
| 152 | rowDecoration: pw.BoxDecoration( | 152 | rowDecoration: pw.BoxDecoration( |
| 153 | - border: pw.BoxBorder( | ||
| 154 | - bottom: true, | ||
| 155 | - color: baseColor, | ||
| 156 | - width: .5, | 153 | + border: pw.Border( |
| 154 | + bottom: pw.BorderSide( | ||
| 155 | + color: baseColor, | ||
| 156 | + width: .5, | ||
| 157 | + ), | ||
| 157 | ), | 158 | ), |
| 158 | ), | 159 | ), |
| 159 | ); | 160 | ); |
| @@ -237,7 +237,7 @@ class _Block extends pw.StatelessWidget { | @@ -237,7 +237,7 @@ class _Block extends pw.StatelessWidget { | ||
| 237 | ]), | 237 | ]), |
| 238 | pw.Container( | 238 | pw.Container( |
| 239 | decoration: const pw.BoxDecoration( | 239 | decoration: const pw.BoxDecoration( |
| 240 | - border: pw.BoxBorder(left: true, color: green, width: 2)), | 240 | + border: pw.Border(left: pw.BorderSide(color: green, width: 2))), |
| 241 | padding: const pw.EdgeInsets.only(left: 10, top: 5, bottom: 5), | 241 | padding: const pw.EdgeInsets.only(left: 10, top: 5, bottom: 5), |
| 242 | margin: const pw.EdgeInsets.only(left: 5), | 242 | margin: const pw.EdgeInsets.only(left: 5), |
| 243 | child: pw.Column( | 243 | child: pw.Column( |
| @@ -220,6 +220,24 @@ class PdfColor { | @@ -220,6 +220,24 @@ class PdfColor { | ||
| 220 | 220 | ||
| 221 | @override | 221 | @override |
| 222 | String toString() => '$runtimeType($red, $green, $blue, $alpha)'; | 222 | String toString() => '$runtimeType($red, $green, $blue, $alpha)'; |
| 223 | + | ||
| 224 | + @override | ||
| 225 | + bool operator ==(Object other) { | ||
| 226 | + if (identical(this, other)) { | ||
| 227 | + return true; | ||
| 228 | + } | ||
| 229 | + if (other.runtimeType != runtimeType) { | ||
| 230 | + return false; | ||
| 231 | + } | ||
| 232 | + return other is PdfColor && | ||
| 233 | + other.red == red && | ||
| 234 | + other.green == green && | ||
| 235 | + other.blue == blue && | ||
| 236 | + other.alpha == alpha; | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + @override | ||
| 240 | + int get hashCode => toInt(); | ||
| 223 | } | 241 | } |
| 224 | 242 | ||
| 225 | /// Represents an CMYK color | 243 | /// Represents an CMYK color |
| @@ -19,6 +19,8 @@ export 'package:barcode/barcode.dart'; | @@ -19,6 +19,8 @@ export 'package:barcode/barcode.dart'; | ||
| 19 | export 'widgets/annotations.dart'; | 19 | export 'widgets/annotations.dart'; |
| 20 | export 'widgets/barcode.dart'; | 20 | export 'widgets/barcode.dart'; |
| 21 | export 'widgets/basic.dart'; | 21 | export 'widgets/basic.dart'; |
| 22 | +export 'widgets/border_radius.dart'; | ||
| 23 | +export 'widgets/box_border.dart'; | ||
| 22 | export 'widgets/chart/bar_chart.dart'; | 24 | export 'widgets/chart/bar_chart.dart'; |
| 23 | export 'widgets/chart/chart.dart'; | 25 | export 'widgets/chart/chart.dart'; |
| 24 | export 'widgets/chart/grid_axis.dart'; | 26 | export 'widgets/chart/grid_axis.dart'; |
| @@ -20,6 +20,7 @@ import 'package:meta/meta.dart'; | @@ -20,6 +20,7 @@ import 'package:meta/meta.dart'; | ||
| 20 | import 'package:pdf/pdf.dart'; | 20 | import 'package:pdf/pdf.dart'; |
| 21 | import 'package:vector_math/vector_math_64.dart'; | 21 | import 'package:vector_math/vector_math_64.dart'; |
| 22 | 22 | ||
| 23 | +import 'box_border.dart'; | ||
| 23 | import 'container.dart'; | 24 | import 'container.dart'; |
| 24 | import 'decoration.dart'; | 25 | import 'decoration.dart'; |
| 25 | import 'geometry.dart'; | 26 | import 'geometry.dart'; |
| @@ -815,10 +816,11 @@ class Divider extends StatelessWidget { | @@ -815,10 +816,11 @@ class Divider extends StatelessWidget { | ||
| 815 | height: thickness, | 816 | height: thickness, |
| 816 | margin: EdgeInsets.only(left: indent, right: endIndent), | 817 | margin: EdgeInsets.only(left: indent, right: endIndent), |
| 817 | decoration: BoxDecoration( | 818 | decoration: BoxDecoration( |
| 818 | - border: BoxBorder( | ||
| 819 | - bottom: true, | ||
| 820 | - color: color, | ||
| 821 | - width: thickness, | 819 | + border: Border( |
| 820 | + bottom: BorderSide( | ||
| 821 | + color: color, | ||
| 822 | + width: thickness, | ||
| 823 | + ), | ||
| 822 | ), | 824 | ), |
| 823 | ), | 825 | ), |
| 824 | ), | 826 | ), |
| @@ -869,10 +871,11 @@ class VerticalDivider extends StatelessWidget { | @@ -869,10 +871,11 @@ class VerticalDivider extends StatelessWidget { | ||
| 869 | width: thickness, | 871 | width: thickness, |
| 870 | margin: EdgeInsets.only(top: indent, bottom: endIndent), | 872 | margin: EdgeInsets.only(top: indent, bottom: endIndent), |
| 871 | decoration: BoxDecoration( | 873 | decoration: BoxDecoration( |
| 872 | - border: BoxBorder( | ||
| 873 | - left: true, | ||
| 874 | - color: color, | ||
| 875 | - width: thickness, | 874 | + border: Border( |
| 875 | + left: BorderSide( | ||
| 876 | + color: color, | ||
| 877 | + width: thickness, | ||
| 878 | + ), | ||
| 876 | ), | 879 | ), |
| 877 | ), | 880 | ), |
| 878 | ), | 881 | ), |
pdf/lib/widgets/border_radius.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 'package:pdf/pdf.dart'; | ||
| 18 | + | ||
| 19 | +import 'widget.dart'; | ||
| 20 | + | ||
| 21 | +/// A radius for either circular or elliptical shapes. | ||
| 22 | +class Radius { | ||
| 23 | + /// Constructs a circular radius. [x] and [y] will have the same radius value. | ||
| 24 | + const Radius.circular(double radius) : this.elliptical(radius, radius); | ||
| 25 | + | ||
| 26 | + /// Constructs an elliptical radius with the given radii. | ||
| 27 | + const Radius.elliptical(this.x, this.y); | ||
| 28 | + | ||
| 29 | + /// The radius value on the horizontal axis. | ||
| 30 | + final double x; | ||
| 31 | + | ||
| 32 | + /// The radius value on the vertical axis. | ||
| 33 | + final double y; | ||
| 34 | + | ||
| 35 | + /// A radius with [x] and [y] values set to zero. | ||
| 36 | + static const Radius zero = Radius.circular(0.0); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +/// An immutable set of radii for each corner of a rectangle. | ||
| 40 | +class BorderRadius { | ||
| 41 | + /// Creates a border radius where all radii are [radius]. | ||
| 42 | + const BorderRadius.all(Radius radius) | ||
| 43 | + : this.only( | ||
| 44 | + topLeft: radius, | ||
| 45 | + topRight: radius, | ||
| 46 | + bottomLeft: radius, | ||
| 47 | + bottomRight: radius, | ||
| 48 | + ); | ||
| 49 | + | ||
| 50 | + /// Creates a border radius where all radii are [Radius.circular(radius)]. | ||
| 51 | + BorderRadius.circular(double radius) | ||
| 52 | + : this.all( | ||
| 53 | + Radius.circular(radius), | ||
| 54 | + ); | ||
| 55 | + | ||
| 56 | + /// Creates a vertically symmetric border radius where the top and bottom | ||
| 57 | + /// sides of the rectangle have the same radii. | ||
| 58 | + const BorderRadius.vertical({ | ||
| 59 | + Radius top = Radius.zero, | ||
| 60 | + Radius bottom = Radius.zero, | ||
| 61 | + }) : this.only( | ||
| 62 | + topLeft: top, | ||
| 63 | + topRight: top, | ||
| 64 | + bottomLeft: bottom, | ||
| 65 | + bottomRight: bottom, | ||
| 66 | + ); | ||
| 67 | + | ||
| 68 | + /// Creates a horizontally symmetrical border radius where the left and right | ||
| 69 | + /// sides of the rectangle have the same radii. | ||
| 70 | + const BorderRadius.horizontal({ | ||
| 71 | + Radius left = Radius.zero, | ||
| 72 | + Radius right = Radius.zero, | ||
| 73 | + }) : this.only( | ||
| 74 | + topLeft: left, | ||
| 75 | + topRight: right, | ||
| 76 | + bottomLeft: left, | ||
| 77 | + bottomRight: right, | ||
| 78 | + ); | ||
| 79 | + | ||
| 80 | + /// Creates a border radius with only the given non-zero values. The other | ||
| 81 | + /// corners will be right angles. | ||
| 82 | + const BorderRadius.only({ | ||
| 83 | + this.topLeft = Radius.zero, | ||
| 84 | + this.topRight = Radius.zero, | ||
| 85 | + this.bottomLeft = Radius.zero, | ||
| 86 | + this.bottomRight = Radius.zero, | ||
| 87 | + }); | ||
| 88 | + | ||
| 89 | + /// A border radius with all zero radii. | ||
| 90 | + static const BorderRadius zero = BorderRadius.all(Radius.zero); | ||
| 91 | + | ||
| 92 | + /// The top-left [Radius]. | ||
| 93 | + final Radius topLeft; | ||
| 94 | + | ||
| 95 | + /// The top-right [Radius]. | ||
| 96 | + final Radius topRight; | ||
| 97 | + | ||
| 98 | + /// The bottom-left [Radius]. | ||
| 99 | + final Radius bottomLeft; | ||
| 100 | + | ||
| 101 | + /// The bottom-right [Radius]. | ||
| 102 | + final Radius bottomRight; | ||
| 103 | + | ||
| 104 | + void paint(Context context, PdfRect box) { | ||
| 105 | + // Ellipse 4-spline magic number | ||
| 106 | + const _m4 = 0.551784; | ||
| 107 | + | ||
| 108 | + context.canvas | ||
| 109 | + // Start | ||
| 110 | + ..moveTo(box.x, box.y + bottomLeft.y) | ||
| 111 | + // bottomLeft | ||
| 112 | + ..curveTo( | ||
| 113 | + box.x, | ||
| 114 | + box.y - _m4 * bottomLeft.y + bottomLeft.y, | ||
| 115 | + box.x - _m4 * bottomLeft.x + bottomLeft.x, | ||
| 116 | + box.y, | ||
| 117 | + box.x + bottomLeft.x, | ||
| 118 | + box.y) | ||
| 119 | + // bottom | ||
| 120 | + ..lineTo(box.x + box.width - bottomRight.x, box.y) | ||
| 121 | + // bottomRight | ||
| 122 | + ..curveTo( | ||
| 123 | + box.x + _m4 * bottomRight.x + box.width - bottomRight.x, | ||
| 124 | + box.y, | ||
| 125 | + box.x + box.width, | ||
| 126 | + box.y - _m4 * bottomRight.y + bottomRight.y, | ||
| 127 | + box.x + box.width, | ||
| 128 | + box.y + bottomRight.y) | ||
| 129 | + // right | ||
| 130 | + ..lineTo(box.x + box.width, box.y + box.height - topRight.y) | ||
| 131 | + // topRight | ||
| 132 | + ..curveTo( | ||
| 133 | + box.x + box.width, | ||
| 134 | + box.y + _m4 * topRight.y + box.height - topRight.y, | ||
| 135 | + box.x + _m4 * topRight.x + box.width - topRight.x, | ||
| 136 | + box.y + box.height, | ||
| 137 | + box.x + box.width - topRight.x, | ||
| 138 | + box.y + box.height) | ||
| 139 | + // top | ||
| 140 | + ..lineTo(box.x + topLeft.x, box.y + box.height) | ||
| 141 | + // topLeft | ||
| 142 | + ..curveTo( | ||
| 143 | + box.x - _m4 * topLeft.x + topLeft.x, | ||
| 144 | + box.y + box.height, | ||
| 145 | + box.x, | ||
| 146 | + box.y + _m4 * topLeft.y + box.height - topLeft.y, | ||
| 147 | + box.x, | ||
| 148 | + box.y + box.height - topLeft.y) | ||
| 149 | + // left | ||
| 150 | + ..lineTo(box.x, box.y + bottomLeft.y); | ||
| 151 | + } | ||
| 152 | +} |
pdf/lib/widgets/box_border.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 'package:meta/meta.dart'; | ||
| 18 | +import 'package:pdf/pdf.dart'; | ||
| 19 | + | ||
| 20 | +import 'border_radius.dart'; | ||
| 21 | +import 'decoration.dart'; | ||
| 22 | +import 'widget.dart'; | ||
| 23 | + | ||
| 24 | +enum BorderStyle { none, solid, dashed, dotted } | ||
| 25 | + | ||
| 26 | +@immutable | ||
| 27 | +abstract class BoxBorder { | ||
| 28 | + @Deprecated('Use Border instead') | ||
| 29 | + factory BoxBorder({ | ||
| 30 | + bool left = false, | ||
| 31 | + bool top = false, | ||
| 32 | + bool right = false, | ||
| 33 | + bool bottom = false, | ||
| 34 | + PdfColor color = PdfColors.black, | ||
| 35 | + double width = 1.0, | ||
| 36 | + BorderStyle style = BorderStyle.solid, | ||
| 37 | + }) { | ||
| 38 | + assert(color != null); | ||
| 39 | + assert(width != null); | ||
| 40 | + assert(width >= 0.0); | ||
| 41 | + assert(style != null); | ||
| 42 | + | ||
| 43 | + return Border( | ||
| 44 | + top: BorderSide( | ||
| 45 | + color: color, width: width, style: top ? style : BorderStyle.none), | ||
| 46 | + bottom: BorderSide( | ||
| 47 | + color: color, | ||
| 48 | + width: width, | ||
| 49 | + style: bottom ? style : BorderStyle.none), | ||
| 50 | + left: BorderSide( | ||
| 51 | + color: color, width: width, style: left ? style : BorderStyle.none), | ||
| 52 | + right: BorderSide( | ||
| 53 | + color: color, | ||
| 54 | + width: width, | ||
| 55 | + style: right ? style : BorderStyle.none)); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + const BoxBorder.P(); | ||
| 59 | + | ||
| 60 | + BorderSide get top; | ||
| 61 | + BorderSide get bottom; | ||
| 62 | + BorderSide get left; | ||
| 63 | + BorderSide get right; | ||
| 64 | + | ||
| 65 | + bool get isUniform; | ||
| 66 | + | ||
| 67 | + void paint( | ||
| 68 | + Context context, | ||
| 69 | + PdfRect box, { | ||
| 70 | + BoxShape shape = BoxShape.rectangle, | ||
| 71 | + BorderRadius borderRadius, | ||
| 72 | + }); | ||
| 73 | + | ||
| 74 | + static void _setStyle(Context context, BorderStyle style) { | ||
| 75 | + switch (style) { | ||
| 76 | + case BorderStyle.none: | ||
| 77 | + case BorderStyle.solid: | ||
| 78 | + break; | ||
| 79 | + case BorderStyle.dashed: | ||
| 80 | + context.canvas | ||
| 81 | + ..saveContext() | ||
| 82 | + ..setLineDashPattern(const <int>[3, 3]); | ||
| 83 | + break; | ||
| 84 | + case BorderStyle.dotted: | ||
| 85 | + context.canvas | ||
| 86 | + ..saveContext() | ||
| 87 | + ..setLineDashPattern(const <int>[1, 1]); | ||
| 88 | + break; | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + static void _unsetStyle(Context context, BorderStyle style) { | ||
| 93 | + switch (style) { | ||
| 94 | + case BorderStyle.none: | ||
| 95 | + case BorderStyle.solid: | ||
| 96 | + break; | ||
| 97 | + case BorderStyle.dashed: | ||
| 98 | + case BorderStyle.dotted: | ||
| 99 | + context.canvas.restoreContext(); | ||
| 100 | + break; | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + static void _paintUniformBorderWithCircle( | ||
| 105 | + Context context, PdfRect box, BorderSide side) { | ||
| 106 | + _setStyle(context, side.style); | ||
| 107 | + context.canvas | ||
| 108 | + ..setStrokeColor(side.color) | ||
| 109 | + ..setLineWidth(side.width) | ||
| 110 | + ..drawEllipse(box.x + box.width / 2.0, box.y + box.height / 2.0, | ||
| 111 | + box.width / 2.0, box.height / 2.0) | ||
| 112 | + ..strokePath(); | ||
| 113 | + _unsetStyle(context, side.style); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + static void _paintUniformBorderWithRadius(Context context, PdfRect box, | ||
| 117 | + BorderSide side, BorderRadius borderRadius) { | ||
| 118 | + _setStyle(context, side.style); | ||
| 119 | + context.canvas | ||
| 120 | + ..setStrokeColor(side.color) | ||
| 121 | + ..setLineWidth(side.width); | ||
| 122 | + borderRadius.paint(context, box); | ||
| 123 | + context.canvas.strokePath(); | ||
| 124 | + _unsetStyle(context, side.style); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + static void _paintUniformBorderWithRectangle( | ||
| 128 | + Context context, PdfRect box, BorderSide side) { | ||
| 129 | + _setStyle(context, side.style); | ||
| 130 | + context.canvas | ||
| 131 | + ..setStrokeColor(side.color) | ||
| 132 | + ..setLineWidth(side.width) | ||
| 133 | + ..drawBox(box) | ||
| 134 | + ..strokePath(); | ||
| 135 | + _unsetStyle(context, side.style); | ||
| 136 | + } | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +/// A side of a border of a box. | ||
| 140 | +class BorderSide { | ||
| 141 | + /// Creates the side of a border. | ||
| 142 | + const BorderSide({ | ||
| 143 | + this.color = PdfColors.black, | ||
| 144 | + this.width = 1.0, | ||
| 145 | + this.style = BorderStyle.solid, | ||
| 146 | + }); | ||
| 147 | + | ||
| 148 | + /// A hairline black border that is not rendered. | ||
| 149 | + static const BorderSide none = | ||
| 150 | + BorderSide(width: 0.0, style: BorderStyle.none); | ||
| 151 | + | ||
| 152 | + /// The color of this side of the border. | ||
| 153 | + final PdfColor color; | ||
| 154 | + | ||
| 155 | + /// The width of this side of the border. | ||
| 156 | + final double width; | ||
| 157 | + | ||
| 158 | + /// The style of this side of the border. | ||
| 159 | + final BorderStyle style; | ||
| 160 | + | ||
| 161 | + BorderSide copyWith({ | ||
| 162 | + PdfColor color, | ||
| 163 | + double width, | ||
| 164 | + BorderStyle style, | ||
| 165 | + }) => | ||
| 166 | + BorderSide( | ||
| 167 | + color: color, | ||
| 168 | + width: width, | ||
| 169 | + style: style, | ||
| 170 | + ); | ||
| 171 | + | ||
| 172 | + @override | ||
| 173 | + bool operator ==(Object other) { | ||
| 174 | + if (identical(this, other)) { | ||
| 175 | + return true; | ||
| 176 | + } | ||
| 177 | + if (other.runtimeType != runtimeType) { | ||
| 178 | + return false; | ||
| 179 | + } | ||
| 180 | + return other is BorderSide && | ||
| 181 | + other.color == color && | ||
| 182 | + other.width == width && | ||
| 183 | + other.style == style; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + @override | ||
| 187 | + int get hashCode => color.hashCode + width.hashCode + style.hashCode; | ||
| 188 | +} | ||
| 189 | + | ||
| 190 | +/// A border of a box, comprised of four sides: top, right, bottom, left. | ||
| 191 | +class Border extends BoxBorder { | ||
| 192 | + const Border({ | ||
| 193 | + this.top = BorderSide.none, | ||
| 194 | + this.right = BorderSide.none, | ||
| 195 | + this.bottom = BorderSide.none, | ||
| 196 | + this.left = BorderSide.none, | ||
| 197 | + }) : assert(top != null), | ||
| 198 | + assert(right != null), | ||
| 199 | + assert(bottom != null), | ||
| 200 | + assert(left != null), | ||
| 201 | + super.P(); | ||
| 202 | + | ||
| 203 | + /// A uniform border with all sides the same color and width. | ||
| 204 | + factory Border.all({ | ||
| 205 | + PdfColor color = PdfColors.black, | ||
| 206 | + double width = 1.0, | ||
| 207 | + BorderStyle style = BorderStyle.solid, | ||
| 208 | + }) => | ||
| 209 | + Border.fromBorderSide( | ||
| 210 | + BorderSide(color: color, width: width, style: style), | ||
| 211 | + ); | ||
| 212 | + | ||
| 213 | + /// Creates a border whose sides are all the same. | ||
| 214 | + const Border.fromBorderSide(BorderSide side) | ||
| 215 | + : assert(side != null), | ||
| 216 | + top = side, | ||
| 217 | + right = side, | ||
| 218 | + bottom = side, | ||
| 219 | + left = side, | ||
| 220 | + super.P(); | ||
| 221 | + | ||
| 222 | + /// Creates a border with symmetrical vertical and horizontal sides. | ||
| 223 | + const Border.symmetric({ | ||
| 224 | + BorderSide vertical = BorderSide.none, | ||
| 225 | + BorderSide horizontal = BorderSide.none, | ||
| 226 | + }) : assert(vertical != null), | ||
| 227 | + assert(horizontal != null), | ||
| 228 | + left = vertical, | ||
| 229 | + top = horizontal, | ||
| 230 | + right = vertical, | ||
| 231 | + bottom = horizontal, | ||
| 232 | + super.P(); | ||
| 233 | + | ||
| 234 | + @override | ||
| 235 | + final BorderSide top; | ||
| 236 | + | ||
| 237 | + @override | ||
| 238 | + final BorderSide bottom; | ||
| 239 | + | ||
| 240 | + @override | ||
| 241 | + final BorderSide left; | ||
| 242 | + | ||
| 243 | + @override | ||
| 244 | + final BorderSide right; | ||
| 245 | + | ||
| 246 | + @override | ||
| 247 | + bool get isUniform => top == bottom && bottom == left && left == right; | ||
| 248 | + | ||
| 249 | + @override | ||
| 250 | + void paint( | ||
| 251 | + Context context, | ||
| 252 | + PdfRect box, { | ||
| 253 | + BoxShape shape = BoxShape.rectangle, | ||
| 254 | + BorderRadius borderRadius, | ||
| 255 | + }) { | ||
| 256 | + assert(box.x != null); | ||
| 257 | + assert(box.y != null); | ||
| 258 | + assert(box.width != null); | ||
| 259 | + assert(box.height != null); | ||
| 260 | + | ||
| 261 | + if (isUniform) { | ||
| 262 | + if (top.style == BorderStyle.none) { | ||
| 263 | + return; | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + switch (shape) { | ||
| 267 | + case BoxShape.circle: | ||
| 268 | + assert(borderRadius == null, | ||
| 269 | + 'A borderRadius can only be given for rectangular boxes.'); | ||
| 270 | + BoxBorder._paintUniformBorderWithCircle(context, box, top); | ||
| 271 | + break; | ||
| 272 | + case BoxShape.rectangle: | ||
| 273 | + if (borderRadius != null) { | ||
| 274 | + BoxBorder._paintUniformBorderWithRadius( | ||
| 275 | + context, box, top, borderRadius); | ||
| 276 | + return; | ||
| 277 | + } | ||
| 278 | + BoxBorder._paintUniformBorderWithRectangle(context, box, top); | ||
| 279 | + break; | ||
| 280 | + } | ||
| 281 | + return; | ||
| 282 | + } | ||
| 283 | + | ||
| 284 | + context.canvas..setLineCap(PdfLineCap.square); | ||
| 285 | + | ||
| 286 | + if (top.style != BorderStyle.none) { | ||
| 287 | + BoxBorder._setStyle(context, top.style); | ||
| 288 | + context.canvas | ||
| 289 | + ..setStrokeColor(top.color) | ||
| 290 | + ..setLineWidth(top.width) | ||
| 291 | + ..drawLine(box.left, box.top, box.right, box.top) | ||
| 292 | + ..strokePath(); | ||
| 293 | + BoxBorder._unsetStyle(context, top.style); | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + if (right.style != BorderStyle.none) { | ||
| 297 | + BoxBorder._setStyle(context, right.style); | ||
| 298 | + context.canvas | ||
| 299 | + ..setStrokeColor(right.color) | ||
| 300 | + ..setLineWidth(right.width) | ||
| 301 | + ..drawLine(box.right, box.top, box.right, box.bottom) | ||
| 302 | + ..strokePath(); | ||
| 303 | + BoxBorder._unsetStyle(context, right.style); | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + if (bottom.style != BorderStyle.none) { | ||
| 307 | + BoxBorder._setStyle(context, bottom.style); | ||
| 308 | + context.canvas | ||
| 309 | + ..setStrokeColor(bottom.color) | ||
| 310 | + ..setLineWidth(bottom.width) | ||
| 311 | + ..drawLine(box.right, box.bottom, box.left, box.bottom) | ||
| 312 | + ..strokePath(); | ||
| 313 | + BoxBorder._unsetStyle(context, bottom.style); | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + if (left.style != BorderStyle.none) { | ||
| 317 | + BoxBorder._setStyle(context, left.style); | ||
| 318 | + context.canvas | ||
| 319 | + ..setStrokeColor(left.color) | ||
| 320 | + ..setLineWidth(left.width) | ||
| 321 | + ..drawLine(box.left, box.top, box.left, box.bottom) | ||
| 322 | + ..strokePath(); | ||
| 323 | + BoxBorder._unsetStyle(context, left.style); | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | +} |
| @@ -18,6 +18,7 @@ import 'package:meta/meta.dart'; | @@ -18,6 +18,7 @@ import 'package:meta/meta.dart'; | ||
| 18 | import 'package:pdf/pdf.dart'; | 18 | import 'package:pdf/pdf.dart'; |
| 19 | import 'package:vector_math/vector_math_64.dart'; | 19 | import 'package:vector_math/vector_math_64.dart'; |
| 20 | 20 | ||
| 21 | +import '../box_border.dart'; | ||
| 21 | import '../container.dart'; | 22 | import '../container.dart'; |
| 22 | import '../decoration.dart'; | 23 | import '../decoration.dart'; |
| 23 | import '../flex.dart'; | 24 | import '../flex.dart'; |
| @@ -21,6 +21,7 @@ import 'package:pdf/pdf.dart'; | @@ -21,6 +21,7 @@ import 'package:pdf/pdf.dart'; | ||
| 21 | 21 | ||
| 22 | import 'annotations.dart'; | 22 | import 'annotations.dart'; |
| 23 | import 'basic.dart'; | 23 | import 'basic.dart'; |
| 24 | +import 'box_border.dart'; | ||
| 24 | import 'container.dart'; | 25 | import 'container.dart'; |
| 25 | import 'decoration.dart'; | 26 | import 'decoration.dart'; |
| 26 | import 'flex.dart'; | 27 | import 'flex.dart'; |
| @@ -78,14 +79,14 @@ class Header extends StatelessWidget { | @@ -78,14 +79,14 @@ class Header extends StatelessWidget { | ||
| 78 | _margin ??= const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm); | 79 | _margin ??= const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm); |
| 79 | _padding ??= const EdgeInsets.only(bottom: 1.0 * PdfPageFormat.mm); | 80 | _padding ??= const EdgeInsets.only(bottom: 1.0 * PdfPageFormat.mm); |
| 80 | _decoration ??= | 81 | _decoration ??= |
| 81 | - const BoxDecoration(border: BoxBorder(bottom: true, width: 1)); | 82 | + const BoxDecoration(border: Border(bottom: BorderSide())); |
| 82 | _textStyle ??= Theme.of(context).header0; | 83 | _textStyle ??= Theme.of(context).header0; |
| 83 | break; | 84 | break; |
| 84 | case 1: | 85 | case 1: |
| 85 | _margin ??= const EdgeInsets.only( | 86 | _margin ??= const EdgeInsets.only( |
| 86 | top: 3.0 * PdfPageFormat.mm, bottom: 5.0 * PdfPageFormat.mm); | 87 | top: 3.0 * PdfPageFormat.mm, bottom: 5.0 * PdfPageFormat.mm); |
| 87 | _decoration ??= | 88 | _decoration ??= |
| 88 | - const BoxDecoration(border: BoxBorder(bottom: true, width: 0.2)); | 89 | + const BoxDecoration(border: Border(bottom: BorderSide(width: 0.2))); |
| 89 | _textStyle ??= Theme.of(context).header1; | 90 | _textStyle ??= Theme.of(context).header1; |
| 90 | break; | 91 | break; |
| 91 | case 2: | 92 | case 2: |
| @@ -22,204 +22,14 @@ import 'package:pdf/pdf.dart'; | @@ -22,204 +22,14 @@ import 'package:pdf/pdf.dart'; | ||
| 22 | import 'package:vector_math/vector_math_64.dart'; | 22 | import 'package:vector_math/vector_math_64.dart'; |
| 23 | 23 | ||
| 24 | import 'basic.dart'; | 24 | import 'basic.dart'; |
| 25 | +import 'border_radius.dart'; | ||
| 26 | +import 'box_border.dart'; | ||
| 25 | import 'geometry.dart'; | 27 | import 'geometry.dart'; |
| 26 | import 'image_provider.dart'; | 28 | import 'image_provider.dart'; |
| 27 | import 'widget.dart'; | 29 | import 'widget.dart'; |
| 28 | 30 | ||
| 29 | enum DecorationPosition { background, foreground } | 31 | enum DecorationPosition { background, foreground } |
| 30 | 32 | ||
| 31 | -enum BorderStyle { none, solid, dashed, dotted } | ||
| 32 | - | ||
| 33 | -@immutable | ||
| 34 | -class BoxBorder { | ||
| 35 | - const BoxBorder({ | ||
| 36 | - this.left = false, | ||
| 37 | - this.top = false, | ||
| 38 | - this.right = false, | ||
| 39 | - this.bottom = false, | ||
| 40 | - this.color = PdfColors.black, | ||
| 41 | - this.width = 1.0, | ||
| 42 | - this.style = BorderStyle.solid, | ||
| 43 | - }) : assert(color != null), | ||
| 44 | - assert(width != null), | ||
| 45 | - assert(width >= 0.0), | ||
| 46 | - assert(style != null); | ||
| 47 | - | ||
| 48 | - final bool top; | ||
| 49 | - final bool bottom; | ||
| 50 | - final bool left; | ||
| 51 | - final bool right; | ||
| 52 | - | ||
| 53 | - final BorderStyle style; | ||
| 54 | - | ||
| 55 | - /// The color of the | ||
| 56 | - final PdfColor color; | ||
| 57 | - | ||
| 58 | - /// The width of the | ||
| 59 | - final double width; | ||
| 60 | - | ||
| 61 | - void paintRect(Context context, PdfRect box) { | ||
| 62 | - assert(box.x != null); | ||
| 63 | - assert(box.y != null); | ||
| 64 | - assert(box.width != null); | ||
| 65 | - assert(box.height != null); | ||
| 66 | - | ||
| 67 | - if (!(top || bottom || left || right)) { | ||
| 68 | - return; | ||
| 69 | - } | ||
| 70 | - | ||
| 71 | - switch (style) { | ||
| 72 | - case BorderStyle.none: | ||
| 73 | - return; | ||
| 74 | - case BorderStyle.solid: | ||
| 75 | - break; | ||
| 76 | - case BorderStyle.dashed: | ||
| 77 | - context.canvas | ||
| 78 | - ..saveContext() | ||
| 79 | - ..setLineDashPattern(const <int>[3, 3]); | ||
| 80 | - break; | ||
| 81 | - case BorderStyle.dotted: | ||
| 82 | - context.canvas | ||
| 83 | - ..saveContext() | ||
| 84 | - ..setLineDashPattern(const <int>[1, 1]); | ||
| 85 | - break; | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - context.canvas | ||
| 89 | - ..setStrokeColor(color) | ||
| 90 | - ..setLineWidth(width); | ||
| 91 | - | ||
| 92 | - if (top) { | ||
| 93 | - context.canvas.drawLine(box.x, box.top, box.right, box.top); | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - if (right) { | ||
| 97 | - if (!top) { | ||
| 98 | - context.canvas.moveTo(box.right, box.top); | ||
| 99 | - } | ||
| 100 | - context.canvas.lineTo(box.right, box.y); | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - if (bottom) { | ||
| 104 | - if (!right) { | ||
| 105 | - context.canvas.moveTo(box.right, box.y); | ||
| 106 | - } | ||
| 107 | - context.canvas.lineTo(box.x, box.y); | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - if (left) { | ||
| 111 | - if (!bottom) { | ||
| 112 | - context.canvas.moveTo(box.x, box.y); | ||
| 113 | - context.canvas.lineTo(box.x, box.top); | ||
| 114 | - } else if (right && top) { | ||
| 115 | - context.canvas.strokePath(close: true); | ||
| 116 | - } else { | ||
| 117 | - context.canvas.lineTo(box.x, box.top); | ||
| 118 | - } | ||
| 119 | - } | ||
| 120 | - | ||
| 121 | - context.canvas.strokePath(); | ||
| 122 | - if (style != BorderStyle.solid) { | ||
| 123 | - context.canvas.restoreContext(); | ||
| 124 | - } | ||
| 125 | - } | ||
| 126 | - | ||
| 127 | - void paintEllipse(Context context, PdfRect box) { | ||
| 128 | - assert(box.x != null); | ||
| 129 | - assert(box.y != null); | ||
| 130 | - assert(box.width != null); | ||
| 131 | - assert(box.height != null); | ||
| 132 | - | ||
| 133 | - context.canvas | ||
| 134 | - ..setStrokeColor(color) | ||
| 135 | - ..setLineWidth(width) | ||
| 136 | - ..drawEllipse(box.x + box.width / 2.0, box.y + box.height / 2.0, | ||
| 137 | - box.width / 2.0, box.height / 2.0) | ||
| 138 | - ..strokePath(); | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - void paintRRect(Context context, PdfRect box, BorderRadius borderRadius) { | ||
| 142 | - assert(box.x != null); | ||
| 143 | - assert(box.y != null); | ||
| 144 | - assert(box.width != null); | ||
| 145 | - assert(box.height != null); | ||
| 146 | - | ||
| 147 | - context.canvas | ||
| 148 | - ..setStrokeColor(color) | ||
| 149 | - ..setLineWidth(width); | ||
| 150 | - borderRadius.paint(context, box); | ||
| 151 | - context.canvas.strokePath(); | ||
| 152 | - } | ||
| 153 | -} | ||
| 154 | - | ||
| 155 | -/// A side of a border of a box. | ||
| 156 | -class BorderSide { | ||
| 157 | - /// Creates the side of a border. | ||
| 158 | - const BorderSide({ | ||
| 159 | - this.color = PdfColors.black, | ||
| 160 | - this.width = 1.0, | ||
| 161 | - this.style = BorderStyle.solid, | ||
| 162 | - }); | ||
| 163 | - | ||
| 164 | - /// The color of this side of the border. | ||
| 165 | - final PdfColor color; | ||
| 166 | - | ||
| 167 | - /// The width of this side of the border. | ||
| 168 | - final double width; | ||
| 169 | - | ||
| 170 | - /// The style of this side of the border. | ||
| 171 | - final BorderStyle style; | ||
| 172 | - | ||
| 173 | - BorderSide copyWith({ | ||
| 174 | - PdfColor color, | ||
| 175 | - double width, | ||
| 176 | - BorderStyle style, | ||
| 177 | - }) => | ||
| 178 | - BorderSide( | ||
| 179 | - color: color, | ||
| 180 | - width: width, | ||
| 181 | - style: style, | ||
| 182 | - ); | ||
| 183 | -} | ||
| 184 | - | ||
| 185 | -/// A border of a box, comprised of four sides: top, right, bottom, left. | ||
| 186 | -class Border extends BoxBorder { | ||
| 187 | - const Border._(bool left, bool top, bool right, bool bottom, PdfColor color, | ||
| 188 | - double width, BorderStyle style) | ||
| 189 | - : super( | ||
| 190 | - left: left, | ||
| 191 | - top: top, | ||
| 192 | - right: right, | ||
| 193 | - bottom: bottom, | ||
| 194 | - color: color, | ||
| 195 | - width: width, | ||
| 196 | - style: style, | ||
| 197 | - ); | ||
| 198 | - | ||
| 199 | - /// A uniform border with all sides the same color and width. | ||
| 200 | - factory Border.all({ | ||
| 201 | - PdfColor color = PdfColors.black, | ||
| 202 | - double width = 1.0, | ||
| 203 | - BorderStyle style = BorderStyle.solid, | ||
| 204 | - }) => | ||
| 205 | - Border._( | ||
| 206 | - true, | ||
| 207 | - true, | ||
| 208 | - true, | ||
| 209 | - true, | ||
| 210 | - color, | ||
| 211 | - width, | ||
| 212 | - style, | ||
| 213 | - ); | ||
| 214 | - | ||
| 215 | - /// Creates a border whose sides are all the same. | ||
| 216 | - factory Border.fromBorderSide(BorderSide side) => Border.all( | ||
| 217 | - color: side.color, | ||
| 218 | - width: side.width, | ||
| 219 | - style: side.style, | ||
| 220 | - ); | ||
| 221 | -} | ||
| 222 | - | ||
| 223 | @immutable | 33 | @immutable |
| 224 | class DecorationImage { | 34 | class DecorationImage { |
| 225 | @Deprecated('Use DecorationImage.provider()') | 35 | @Deprecated('Use DecorationImage.provider()') |
| @@ -498,139 +308,6 @@ enum BoxShape { circle, rectangle } | @@ -498,139 +308,6 @@ enum BoxShape { circle, rectangle } | ||
| 498 | 308 | ||
| 499 | enum PaintPhase { all, background, foreground } | 309 | enum PaintPhase { all, background, foreground } |
| 500 | 310 | ||
| 501 | -/// A radius for either circular or elliptical shapes. | ||
| 502 | -class Radius { | ||
| 503 | - /// Constructs a circular radius. [x] and [y] will have the same radius value. | ||
| 504 | - const Radius.circular(double radius) : this.elliptical(radius, radius); | ||
| 505 | - | ||
| 506 | - /// Constructs an elliptical radius with the given radii. | ||
| 507 | - const Radius.elliptical(this.x, this.y); | ||
| 508 | - | ||
| 509 | - /// The radius value on the horizontal axis. | ||
| 510 | - final double x; | ||
| 511 | - | ||
| 512 | - /// The radius value on the vertical axis. | ||
| 513 | - final double y; | ||
| 514 | - | ||
| 515 | - /// A radius with [x] and [y] values set to zero. | ||
| 516 | - static const Radius zero = Radius.circular(0.0); | ||
| 517 | -} | ||
| 518 | - | ||
| 519 | -/// An immutable set of radii for each corner of a rectangle. | ||
| 520 | -class BorderRadius { | ||
| 521 | - /// Creates a border radius where all radii are [radius]. | ||
| 522 | - const BorderRadius.all(Radius radius) | ||
| 523 | - : this.only( | ||
| 524 | - topLeft: radius, | ||
| 525 | - topRight: radius, | ||
| 526 | - bottomLeft: radius, | ||
| 527 | - bottomRight: radius, | ||
| 528 | - ); | ||
| 529 | - | ||
| 530 | - /// Creates a border radius where all radii are [Radius.circular(radius)]. | ||
| 531 | - BorderRadius.circular(double radius) | ||
| 532 | - : this.all( | ||
| 533 | - Radius.circular(radius), | ||
| 534 | - ); | ||
| 535 | - | ||
| 536 | - /// Creates a vertically symmetric border radius where the top and bottom | ||
| 537 | - /// sides of the rectangle have the same radii. | ||
| 538 | - const BorderRadius.vertical({ | ||
| 539 | - Radius top = Radius.zero, | ||
| 540 | - Radius bottom = Radius.zero, | ||
| 541 | - }) : this.only( | ||
| 542 | - topLeft: top, | ||
| 543 | - topRight: top, | ||
| 544 | - bottomLeft: bottom, | ||
| 545 | - bottomRight: bottom, | ||
| 546 | - ); | ||
| 547 | - | ||
| 548 | - /// Creates a horizontally symmetrical border radius where the left and right | ||
| 549 | - /// sides of the rectangle have the same radii. | ||
| 550 | - const BorderRadius.horizontal({ | ||
| 551 | - Radius left = Radius.zero, | ||
| 552 | - Radius right = Radius.zero, | ||
| 553 | - }) : this.only( | ||
| 554 | - topLeft: left, | ||
| 555 | - topRight: right, | ||
| 556 | - bottomLeft: left, | ||
| 557 | - bottomRight: right, | ||
| 558 | - ); | ||
| 559 | - | ||
| 560 | - /// Creates a border radius with only the given non-zero values. The other | ||
| 561 | - /// corners will be right angles. | ||
| 562 | - const BorderRadius.only({ | ||
| 563 | - this.topLeft = Radius.zero, | ||
| 564 | - this.topRight = Radius.zero, | ||
| 565 | - this.bottomLeft = Radius.zero, | ||
| 566 | - this.bottomRight = Radius.zero, | ||
| 567 | - }); | ||
| 568 | - | ||
| 569 | - /// A border radius with all zero radii. | ||
| 570 | - static const BorderRadius zero = BorderRadius.all(Radius.zero); | ||
| 571 | - | ||
| 572 | - /// The top-left [Radius]. | ||
| 573 | - final Radius topLeft; | ||
| 574 | - | ||
| 575 | - /// The top-right [Radius]. | ||
| 576 | - final Radius topRight; | ||
| 577 | - | ||
| 578 | - /// The bottom-left [Radius]. | ||
| 579 | - final Radius bottomLeft; | ||
| 580 | - | ||
| 581 | - /// The bottom-right [Radius]. | ||
| 582 | - final Radius bottomRight; | ||
| 583 | - | ||
| 584 | - void paint(Context context, PdfRect box) { | ||
| 585 | - // Ellipse 4-spline magic number | ||
| 586 | - const _m4 = 0.551784; | ||
| 587 | - | ||
| 588 | - context.canvas | ||
| 589 | - // Start | ||
| 590 | - ..moveTo(box.x, box.y + bottomLeft.y) | ||
| 591 | - // bottomLeft | ||
| 592 | - ..curveTo( | ||
| 593 | - box.x, | ||
| 594 | - box.y - _m4 * bottomLeft.y + bottomLeft.y, | ||
| 595 | - box.x - _m4 * bottomLeft.x + bottomLeft.x, | ||
| 596 | - box.y, | ||
| 597 | - box.x + bottomLeft.x, | ||
| 598 | - box.y) | ||
| 599 | - // bottom | ||
| 600 | - ..lineTo(box.x + box.width - bottomRight.x, box.y) | ||
| 601 | - // bottomRight | ||
| 602 | - ..curveTo( | ||
| 603 | - box.x + _m4 * bottomRight.x + box.width - bottomRight.x, | ||
| 604 | - box.y, | ||
| 605 | - box.x + box.width, | ||
| 606 | - box.y - _m4 * bottomRight.y + bottomRight.y, | ||
| 607 | - box.x + box.width, | ||
| 608 | - box.y + bottomRight.y) | ||
| 609 | - // right | ||
| 610 | - ..lineTo(box.x + box.width, box.y + box.height - topRight.y) | ||
| 611 | - // topRight | ||
| 612 | - ..curveTo( | ||
| 613 | - box.x + box.width, | ||
| 614 | - box.y + _m4 * topRight.y + box.height - topRight.y, | ||
| 615 | - box.x + _m4 * topRight.x + box.width - topRight.x, | ||
| 616 | - box.y + box.height, | ||
| 617 | - box.x + box.width - topRight.x, | ||
| 618 | - box.y + box.height) | ||
| 619 | - // top | ||
| 620 | - ..lineTo(box.x + topLeft.x, box.y + box.height) | ||
| 621 | - // topLeft | ||
| 622 | - ..curveTo( | ||
| 623 | - box.x - _m4 * topLeft.x + topLeft.x, | ||
| 624 | - box.y + box.height, | ||
| 625 | - box.x, | ||
| 626 | - box.y + _m4 * topLeft.y + box.height - topLeft.y, | ||
| 627 | - box.x, | ||
| 628 | - box.y + box.height - topLeft.y) | ||
| 629 | - // left | ||
| 630 | - ..lineTo(box.x, box.y + bottomLeft.y); | ||
| 631 | - } | ||
| 632 | -} | ||
| 633 | - | ||
| 634 | @immutable | 311 | @immutable |
| 635 | class BoxDecoration { | 312 | class BoxDecoration { |
| 636 | const BoxDecoration({ | 313 | const BoxDecoration({ |
| @@ -768,18 +445,12 @@ class BoxDecoration { | @@ -768,18 +445,12 @@ class BoxDecoration { | ||
| 768 | 445 | ||
| 769 | if (phase == PaintPhase.all || phase == PaintPhase.foreground) { | 446 | if (phase == PaintPhase.all || phase == PaintPhase.foreground) { |
| 770 | if (border != null) { | 447 | if (border != null) { |
| 771 | - switch (shape) { | ||
| 772 | - case BoxShape.circle: | ||
| 773 | - border.paintEllipse(context, box); | ||
| 774 | - break; | ||
| 775 | - case BoxShape.rectangle: | ||
| 776 | - if (borderRadius != null) { | ||
| 777 | - border.paintRRect(context, box, borderRadius); | ||
| 778 | - } else { | ||
| 779 | - border.paintRect(context, box); | ||
| 780 | - } | ||
| 781 | - break; | ||
| 782 | - } | 448 | + border.paint( |
| 449 | + context, | ||
| 450 | + box, | ||
| 451 | + shape: shape, | ||
| 452 | + borderRadius: borderRadius, | ||
| 453 | + ); | ||
| 783 | } | 454 | } |
| 784 | } | 455 | } |
| 785 | } | 456 | } |
| @@ -18,6 +18,8 @@ import 'package:meta/meta.dart'; | @@ -18,6 +18,8 @@ import 'package:meta/meta.dart'; | ||
| 18 | import 'package:pdf/pdf.dart'; | 18 | import 'package:pdf/pdf.dart'; |
| 19 | import 'package:vector_math/vector_math_64.dart'; | 19 | import 'package:vector_math/vector_math_64.dart'; |
| 20 | 20 | ||
| 21 | +import 'border_radius.dart'; | ||
| 22 | +import 'box_border.dart'; | ||
| 21 | import 'container.dart'; | 23 | import 'container.dart'; |
| 22 | import 'decoration.dart'; | 24 | import 'decoration.dart'; |
| 23 | import 'geometry.dart'; | 25 | import 'geometry.dart'; |
| @@ -20,6 +20,7 @@ import 'package:meta/meta.dart'; | @@ -20,6 +20,7 @@ import 'package:meta/meta.dart'; | ||
| 20 | import 'package:pdf/pdf.dart'; | 20 | import 'package:pdf/pdf.dart'; |
| 21 | import 'package:vector_math/vector_math_64.dart'; | 21 | import 'package:vector_math/vector_math_64.dart'; |
| 22 | 22 | ||
| 23 | +import 'box_border.dart'; | ||
| 23 | import 'container.dart'; | 24 | import 'container.dart'; |
| 24 | import 'decoration.dart'; | 25 | import 'decoration.dart'; |
| 25 | import 'flex.dart'; | 26 | import 'flex.dart'; |
| @@ -55,32 +56,93 @@ enum TableCellVerticalAlignment { bottom, middle, top, full } | @@ -55,32 +56,93 @@ enum TableCellVerticalAlignment { bottom, middle, top, full } | ||
| 55 | 56 | ||
| 56 | enum TableWidth { min, max } | 57 | enum TableWidth { min, max } |
| 57 | 58 | ||
| 58 | -class TableBorder extends BoxBorder { | ||
| 59 | - const TableBorder( | 59 | +class TableBorder extends Border { |
| 60 | + /// Creates a border for a table. | ||
| 61 | + @Deprecated('Use TableBorder.ex instead') | ||
| 62 | + TableBorder( | ||
| 60 | {bool left = true, | 63 | {bool left = true, |
| 61 | bool top = true, | 64 | bool top = true, |
| 62 | bool right = true, | 65 | bool right = true, |
| 63 | bool bottom = true, | 66 | bool bottom = true, |
| 64 | - this.horizontalInside = true, | ||
| 65 | - this.verticalInside = true, | 67 | + bool horizontalInside = true, |
| 68 | + bool verticalInside = true, | ||
| 66 | PdfColor color = PdfColors.black, | 69 | PdfColor color = PdfColors.black, |
| 67 | double width = 1.0}) | 70 | double width = 1.0}) |
| 68 | - : super( | ||
| 69 | - left: left, | ||
| 70 | - top: top, | ||
| 71 | - right: right, | ||
| 72 | - bottom: bottom, | 71 | + : horizontalInside = BorderSide( |
| 73 | color: color, | 72 | color: color, |
| 74 | - width: width); | 73 | + width: width, |
| 74 | + style: horizontalInside ? BorderStyle.solid : BorderStyle.none), | ||
| 75 | + verticalInside = BorderSide( | ||
| 76 | + color: color, | ||
| 77 | + width: width, | ||
| 78 | + style: verticalInside ? BorderStyle.solid : BorderStyle.none), | ||
| 79 | + super( | ||
| 80 | + top: BorderSide( | ||
| 81 | + color: color, | ||
| 82 | + width: width, | ||
| 83 | + style: top ? BorderStyle.solid : BorderStyle.none), | ||
| 84 | + bottom: BorderSide( | ||
| 85 | + color: color, | ||
| 86 | + width: width, | ||
| 87 | + style: bottom ? BorderStyle.solid : BorderStyle.none), | ||
| 88 | + left: BorderSide( | ||
| 89 | + color: color, | ||
| 90 | + width: width, | ||
| 91 | + style: left ? BorderStyle.solid : BorderStyle.none), | ||
| 92 | + right: BorderSide( | ||
| 93 | + color: color, | ||
| 94 | + width: width, | ||
| 95 | + style: right ? BorderStyle.solid : BorderStyle.none)); | ||
| 96 | + | ||
| 97 | + /// Creates a border for a table. | ||
| 98 | + const TableBorder.ex({ | ||
| 99 | + BorderSide left = BorderSide.none, | ||
| 100 | + BorderSide top = BorderSide.none, | ||
| 101 | + BorderSide right = BorderSide.none, | ||
| 102 | + BorderSide bottom = BorderSide.none, | ||
| 103 | + this.horizontalInside = BorderSide.none, | ||
| 104 | + this.verticalInside = BorderSide.none, | ||
| 105 | + }) : super(top: top, bottom: bottom, left: left, right: right); | ||
| 106 | + | ||
| 107 | + /// A uniform border with all sides the same color and width. | ||
| 108 | + factory TableBorder.all({ | ||
| 109 | + PdfColor color = PdfColors.black, | ||
| 110 | + double width = 1.0, | ||
| 111 | + BorderStyle style = BorderStyle.solid, | ||
| 112 | + }) { | ||
| 113 | + final side = BorderSide(color: color, width: width, style: style); | ||
| 114 | + return TableBorder.ex( | ||
| 115 | + top: side, | ||
| 116 | + right: side, | ||
| 117 | + bottom: side, | ||
| 118 | + left: side, | ||
| 119 | + horizontalInside: side, | ||
| 120 | + verticalInside: side); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + /// Creates a border for a table where all the interior sides use the same styling and all the exterior sides use the same styling. | ||
| 124 | + factory TableBorder.symmetric({ | ||
| 125 | + BorderSide inside = BorderSide.none, | ||
| 126 | + BorderSide outside = BorderSide.none, | ||
| 127 | + }) { | ||
| 128 | + return TableBorder.ex( | ||
| 129 | + top: outside, | ||
| 130 | + right: outside, | ||
| 131 | + bottom: outside, | ||
| 132 | + left: outside, | ||
| 133 | + horizontalInside: inside, | ||
| 134 | + verticalInside: inside, | ||
| 135 | + ); | ||
| 136 | + } | ||
| 75 | 137 | ||
| 76 | - final bool horizontalInside; | ||
| 77 | - final bool verticalInside; | 138 | + final BorderSide horizontalInside; |
| 139 | + final BorderSide verticalInside; | ||
| 78 | 140 | ||
| 79 | - void paint(Context context, PdfRect box, | 141 | + void paintTable(Context context, PdfRect box, |
| 80 | [List<double> widths, List<double> heights]) { | 142 | [List<double> widths, List<double> heights]) { |
| 81 | - super.paintRect(context, box); | 143 | + super.paint(context, box); |
| 82 | 144 | ||
| 83 | - if (verticalInside) { | 145 | + if (verticalInside.style != BorderStyle.none) { |
| 84 | var offset = box.x; | 146 | var offset = box.x; |
| 85 | for (var width in widths.sublist(0, widths.length - 1)) { | 147 | for (var width in widths.sublist(0, widths.length - 1)) { |
| 86 | offset += width; | 148 | offset += width; |
| @@ -90,7 +152,7 @@ class TableBorder extends BoxBorder { | @@ -90,7 +152,7 @@ class TableBorder extends BoxBorder { | ||
| 90 | context.canvas.strokePath(); | 152 | context.canvas.strokePath(); |
| 91 | } | 153 | } |
| 92 | 154 | ||
| 93 | - if (horizontalInside) { | 155 | + if (horizontalInside.style != BorderStyle.none) { |
| 94 | var offset = box.top; | 156 | var offset = box.top; |
| 95 | for (var height in heights.sublist(0, heights.length - 1)) { | 157 | for (var height in heights.sublist(0, heights.length - 1)) { |
| 96 | offset -= height; | 158 | offset -= height; |
| @@ -234,7 +296,14 @@ class Table extends Widget implements SpanningWidget { | @@ -234,7 +296,14 @@ class Table extends Widget implements SpanningWidget { | ||
| 234 | Map<int, Alignment> headerAlignments, | 296 | Map<int, Alignment> headerAlignments, |
| 235 | TextStyle headerStyle, | 297 | TextStyle headerStyle, |
| 236 | OnCellFormat headerFormat, | 298 | OnCellFormat headerFormat, |
| 237 | - TableBorder border = const TableBorder(), | 299 | + TableBorder border = const TableBorder.ex( |
| 300 | + left: BorderSide(), | ||
| 301 | + right: BorderSide(), | ||
| 302 | + top: BorderSide(), | ||
| 303 | + bottom: BorderSide(), | ||
| 304 | + horizontalInside: BorderSide(), | ||
| 305 | + verticalInside: BorderSide(), | ||
| 306 | + ), | ||
| 238 | Map<int, TableColumnWidth> columnWidths, | 307 | Map<int, TableColumnWidth> columnWidths, |
| 239 | TableColumnWidth defaultColumnWidth = const IntrinsicColumnWidth(), | 308 | TableColumnWidth defaultColumnWidth = const IntrinsicColumnWidth(), |
| 240 | TableWidth tableWidth = TableWidth.max, | 309 | TableWidth tableWidth = TableWidth.max, |
| @@ -617,7 +686,7 @@ class Table extends Widget implements SpanningWidget { | @@ -617,7 +686,7 @@ class Table extends Widget implements SpanningWidget { | ||
| 617 | context.canvas.restoreContext(); | 686 | context.canvas.restoreContext(); |
| 618 | 687 | ||
| 619 | if (border != null) { | 688 | if (border != null) { |
| 620 | - border.paint(context, box, _widths, _heights); | 689 | + border.paintTable(context, box, _widths, _heights); |
| 621 | } | 690 | } |
| 622 | } | 691 | } |
| 623 | 692 |
| @@ -80,7 +80,7 @@ void main() { | @@ -80,7 +80,7 @@ void main() { | ||
| 80 | pdf.addPage(Page( | 80 | pdf.addPage(Page( |
| 81 | build: (Context context) => Table( | 81 | build: (Context context) => Table( |
| 82 | children: buildTable(context: context, count: 20), | 82 | children: buildTable(context: context, count: 20), |
| 83 | - border: const TableBorder(), | 83 | + border: TableBorder.all(), |
| 84 | tableWidth: TableWidth.max, | 84 | tableWidth: TableWidth.max, |
| 85 | ), | 85 | ), |
| 86 | )); | 86 | )); |
| @@ -91,7 +91,7 @@ void main() { | @@ -91,7 +91,7 @@ void main() { | ||
| 91 | build: (Context context) => <Widget>[ | 91 | build: (Context context) => <Widget>[ |
| 92 | Table( | 92 | Table( |
| 93 | children: buildTable(context: context, count: 200), | 93 | children: buildTable(context: context, count: 200), |
| 94 | - border: const TableBorder(), | 94 | + border: TableBorder.all(), |
| 95 | tableWidth: TableWidth.max, | 95 | tableWidth: TableWidth.max, |
| 96 | ), | 96 | ), |
| 97 | ])); | 97 | ])); |
| @@ -103,7 +103,7 @@ void main() { | @@ -103,7 +103,7 @@ void main() { | ||
| 103 | Table( | 103 | Table( |
| 104 | children: buildTable( | 104 | children: buildTable( |
| 105 | context: context, count: 200, repeatHeader: true), | 105 | context: context, count: 200, repeatHeader: true), |
| 106 | - border: const TableBorder(), | 106 | + border: TableBorder.all(), |
| 107 | tableWidth: TableWidth.max, | 107 | tableWidth: TableWidth.max, |
| 108 | ), | 108 | ), |
| 109 | ])); | 109 | ])); |
| @@ -115,7 +115,7 @@ void main() { | @@ -115,7 +115,7 @@ void main() { | ||
| 115 | SizedBox(height: 710), | 115 | SizedBox(height: 710), |
| 116 | Table( | 116 | Table( |
| 117 | children: buildTable(context: context, count: 4), | 117 | children: buildTable(context: context, count: 4), |
| 118 | - border: const TableBorder(), | 118 | + border: TableBorder.all(), |
| 119 | tableWidth: TableWidth.max, | 119 | tableWidth: TableWidth.max, |
| 120 | ), | 120 | ), |
| 121 | ])); | 121 | ])); |
| @@ -128,7 +128,7 @@ void main() { | @@ -128,7 +128,7 @@ void main() { | ||
| 128 | Table( | 128 | Table( |
| 129 | children: | 129 | children: |
| 130 | buildTable(context: context, count: 4, repeatHeader: true), | 130 | buildTable(context: context, count: 4, repeatHeader: true), |
| 131 | - border: const TableBorder(), | 131 | + border: TableBorder.all(), |
| 132 | tableWidth: TableWidth.max, | 132 | tableWidth: TableWidth.max, |
| 133 | ), | 133 | ), |
| 134 | ])); | 134 | ])); |
| @@ -138,7 +138,7 @@ void main() { | @@ -138,7 +138,7 @@ void main() { | ||
| 138 | pdf.addPage(Page( | 138 | pdf.addPage(Page( |
| 139 | build: (Context context) => Table( | 139 | build: (Context context) => Table( |
| 140 | children: buildTable(context: context, count: 20), | 140 | children: buildTable(context: context, count: 20), |
| 141 | - border: const TableBorder(), | 141 | + border: TableBorder.all(), |
| 142 | columnWidths: <int, TableColumnWidth>{ | 142 | columnWidths: <int, TableColumnWidth>{ |
| 143 | 0: const FixedColumnWidth(80), | 143 | 0: const FixedColumnWidth(80), |
| 144 | 1: const FlexColumnWidth(2), | 144 | 1: const FlexColumnWidth(2), |
| @@ -218,10 +218,11 @@ void main() { | @@ -218,10 +218,11 @@ void main() { | ||
| 218 | fontWeight: FontWeight.bold, | 218 | fontWeight: FontWeight.bold, |
| 219 | ), | 219 | ), |
| 220 | rowDecoration: const BoxDecoration( | 220 | rowDecoration: const BoxDecoration( |
| 221 | - border: BoxBorder( | ||
| 222 | - bottom: true, | ||
| 223 | - color: PdfColors.indigo, | ||
| 224 | - width: .5, | 221 | + border: Border( |
| 222 | + bottom: BorderSide( | ||
| 223 | + color: PdfColors.indigo, | ||
| 224 | + width: .5, | ||
| 225 | + ), | ||
| 225 | ), | 226 | ), |
| 226 | ), | 227 | ), |
| 227 | headers: <dynamic>['One', 'Two', 'Three'], | 228 | headers: <dynamic>['One', 'Two', 'Three'], |
| @@ -108,7 +108,7 @@ void main() { | @@ -108,7 +108,7 @@ void main() { | ||
| 108 | ), | 108 | ), |
| 109 | Container( | 109 | Container( |
| 110 | decoration: | 110 | decoration: |
| 111 | - const BoxDecoration(border: BoxBorder(top: true, width: 1)), | 111 | + const BoxDecoration(border: Border(top: BorderSide())), |
| 112 | child: Text( | 112 | child: Text( |
| 113 | "That's all Folks!", | 113 | "That's all Folks!", |
| 114 | tightBounds: true, | 114 | tightBounds: true, |
No preview for this file type
No preview for this file type
No preview for this file type
-
Please register or login to post a comment