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