Showing
6 changed files
with
711 additions
and
0 deletions
@@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
5 | * Add better debugPaint on Align Widget | 5 | * Add better debugPaint on Align Widget |
6 | * Fix Transform placement when Alignment and Origin are Null | 6 | * Fix Transform placement when Alignment and Origin are Null |
7 | * Add Transform.rotateBox constructor | 7 | * Add Transform.rotateBox constructor |
8 | +* Add Wrap Widget | ||
8 | 9 | ||
9 | ## 1.3.15 | 10 | ## 1.3.15 |
10 | 11 |
@@ -46,6 +46,14 @@ class BoxConstraints { | @@ -46,6 +46,14 @@ class BoxConstraints { | ||
46 | minHeight = height != null ? height : double.infinity, | 46 | minHeight = height != null ? height : double.infinity, |
47 | maxHeight = height != null ? height : double.infinity; | 47 | maxHeight = height != null ? height : double.infinity; |
48 | 48 | ||
49 | + const BoxConstraints.tightForFinite({ | ||
50 | + double width = double.infinity, | ||
51 | + double height = double.infinity, | ||
52 | + }) : minWidth = width != double.infinity ? width : 0.0, | ||
53 | + maxWidth = width != double.infinity ? width : double.infinity, | ||
54 | + minHeight = height != double.infinity ? height : 0.0, | ||
55 | + maxHeight = height != double.infinity ? height : double.infinity; | ||
56 | + | ||
49 | /// The minimum width that satisfies the constraints. | 57 | /// The minimum width that satisfies the constraints. |
50 | final double minWidth; | 58 | final double minWidth; |
51 | 59 |
pdf/lib/widgets/wrap.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +part of widget; | ||
18 | + | ||
19 | +/// How [Wrap] should align objects. | ||
20 | +enum WrapAlignment { | ||
21 | + start, | ||
22 | + end, | ||
23 | + center, | ||
24 | + spaceBetween, | ||
25 | + spaceAround, | ||
26 | + spaceEvenly | ||
27 | +} | ||
28 | + | ||
29 | +/// Who [Wrap] should align children within a run in the cross axis. | ||
30 | +enum WrapCrossAlignment { start, end, center } | ||
31 | + | ||
32 | +class _RunMetrics { | ||
33 | + _RunMetrics(this.mainAxisExtent, this.crossAxisExtent, this.childCount); | ||
34 | + | ||
35 | + final double mainAxisExtent; | ||
36 | + final double crossAxisExtent; | ||
37 | + final int childCount; | ||
38 | +} | ||
39 | + | ||
40 | +/// A widget that displays its children in multiple horizontal or vertical runs. | ||
41 | +class Wrap extends MultiChildWidget { | ||
42 | + /// Creates a wrap layout. | ||
43 | + | ||
44 | + Wrap({ | ||
45 | + this.direction = Axis.horizontal, | ||
46 | + this.alignment = WrapAlignment.start, | ||
47 | + this.spacing = 0.0, | ||
48 | + this.runAlignment = WrapAlignment.start, | ||
49 | + this.runSpacing = 0.0, | ||
50 | + this.crossAxisAlignment = WrapCrossAlignment.start, | ||
51 | + this.verticalDirection = VerticalDirection.down, | ||
52 | + List<Widget> children = const <Widget>[], | ||
53 | + }) : assert(direction != null), | ||
54 | + assert(alignment != null), | ||
55 | + assert(spacing != null), | ||
56 | + assert(runAlignment != null), | ||
57 | + assert(runSpacing != null), | ||
58 | + assert(crossAxisAlignment != null), | ||
59 | + super(children: children); | ||
60 | + | ||
61 | + /// The direction to use as the main axis. | ||
62 | + final Axis direction; | ||
63 | + | ||
64 | + /// How the children within a run should be placed in the main axis. | ||
65 | + final WrapAlignment alignment; | ||
66 | + | ||
67 | + /// How much space to place between children in a run in the main axis. | ||
68 | + final double spacing; | ||
69 | + | ||
70 | + /// How the runs themselves should be placed in the cross axis. | ||
71 | + final WrapAlignment runAlignment; | ||
72 | + | ||
73 | + /// How much space to place between the runs themselves in the cross axis. | ||
74 | + final double runSpacing; | ||
75 | + | ||
76 | + /// How the children within a run should be aligned relative to each other in | ||
77 | + /// the cross axis. | ||
78 | + final WrapCrossAlignment crossAxisAlignment; | ||
79 | + | ||
80 | + /// Determines the order to lay children out vertically and how to interpret | ||
81 | + /// `start` and `end` in the vertical direction. | ||
82 | + final VerticalDirection verticalDirection; | ||
83 | + | ||
84 | + bool get textDirection => false; | ||
85 | + | ||
86 | + bool _hasVisualOverflow = false; | ||
87 | + | ||
88 | + bool get _debugHasNecessaryDirections { | ||
89 | + assert(direction != null); | ||
90 | + assert(alignment != null); | ||
91 | + assert(runAlignment != null); | ||
92 | + assert(crossAxisAlignment != null); | ||
93 | + if (children.length > 1) { | ||
94 | + // i.e. there's more than one child | ||
95 | + switch (direction) { | ||
96 | + case Axis.horizontal: | ||
97 | + assert(textDirection != null, | ||
98 | + 'Horizontal $runtimeType with multiple children has a null textDirection, so the layout order is undefined.'); | ||
99 | + break; | ||
100 | + case Axis.vertical: | ||
101 | + assert(verticalDirection != null, | ||
102 | + 'Vertical $runtimeType with multiple children has a null verticalDirection, so the layout order is undefined.'); | ||
103 | + break; | ||
104 | + } | ||
105 | + } | ||
106 | + if (alignment == WrapAlignment.start || alignment == WrapAlignment.end) { | ||
107 | + switch (direction) { | ||
108 | + case Axis.horizontal: | ||
109 | + assert(textDirection != null, | ||
110 | + 'Horizontal $runtimeType with alignment $alignment has a null textDirection, so the alignment cannot be resolved.'); | ||
111 | + break; | ||
112 | + case Axis.vertical: | ||
113 | + assert(verticalDirection != null, | ||
114 | + 'Vertical $runtimeType with alignment $alignment has a null verticalDirection, so the alignment cannot be resolved.'); | ||
115 | + break; | ||
116 | + } | ||
117 | + } | ||
118 | + if (runAlignment == WrapAlignment.start || | ||
119 | + runAlignment == WrapAlignment.end) { | ||
120 | + switch (direction) { | ||
121 | + case Axis.horizontal: | ||
122 | + assert(verticalDirection != null, | ||
123 | + 'Horizontal $runtimeType with runAlignment $runAlignment has a null verticalDirection, so the alignment cannot be resolved.'); | ||
124 | + break; | ||
125 | + case Axis.vertical: | ||
126 | + assert(textDirection != null, | ||
127 | + 'Vertical $runtimeType with runAlignment $runAlignment has a null textDirection, so the alignment cannot be resolved.'); | ||
128 | + break; | ||
129 | + } | ||
130 | + } | ||
131 | + if (crossAxisAlignment == WrapCrossAlignment.start || | ||
132 | + crossAxisAlignment == WrapCrossAlignment.end) { | ||
133 | + switch (direction) { | ||
134 | + case Axis.horizontal: | ||
135 | + assert(verticalDirection != null, | ||
136 | + 'Horizontal $runtimeType with crossAxisAlignment $crossAxisAlignment has a null verticalDirection, so the alignment cannot be resolved.'); | ||
137 | + break; | ||
138 | + case Axis.vertical: | ||
139 | + assert(textDirection != null, | ||
140 | + 'Vertical $runtimeType with crossAxisAlignment $crossAxisAlignment has a null textDirection, so the alignment cannot be resolved.'); | ||
141 | + break; | ||
142 | + } | ||
143 | + } | ||
144 | + return true; | ||
145 | + } | ||
146 | + | ||
147 | + double _getMainAxisExtent(Widget child) { | ||
148 | + switch (direction) { | ||
149 | + case Axis.horizontal: | ||
150 | + return child.box.width; | ||
151 | + case Axis.vertical: | ||
152 | + return child.box.height; | ||
153 | + } | ||
154 | + return 0.0; | ||
155 | + } | ||
156 | + | ||
157 | + double _getCrossAxisExtent(Widget child) { | ||
158 | + switch (direction) { | ||
159 | + case Axis.horizontal: | ||
160 | + return child.box.height; | ||
161 | + case Axis.vertical: | ||
162 | + return child.box.width; | ||
163 | + } | ||
164 | + return 0.0; | ||
165 | + } | ||
166 | + | ||
167 | + PdfPoint _getOffset(double mainAxisOffset, double crossAxisOffset) { | ||
168 | + switch (direction) { | ||
169 | + case Axis.horizontal: | ||
170 | + return PdfPoint(mainAxisOffset, crossAxisOffset); | ||
171 | + case Axis.vertical: | ||
172 | + return PdfPoint(crossAxisOffset, mainAxisOffset); | ||
173 | + } | ||
174 | + return PdfPoint.zero; | ||
175 | + } | ||
176 | + | ||
177 | + double _getChildCrossAxisOffset(bool flipCrossAxis, double runCrossAxisExtent, | ||
178 | + double childCrossAxisExtent) { | ||
179 | + final double freeSpace = runCrossAxisExtent - childCrossAxisExtent; | ||
180 | + switch (crossAxisAlignment) { | ||
181 | + case WrapCrossAlignment.start: | ||
182 | + return flipCrossAxis ? freeSpace : 0.0; | ||
183 | + case WrapCrossAlignment.end: | ||
184 | + return flipCrossAxis ? 0.0 : freeSpace; | ||
185 | + case WrapCrossAlignment.center: | ||
186 | + return freeSpace / 2.0; | ||
187 | + } | ||
188 | + return 0.0; | ||
189 | + } | ||
190 | + | ||
191 | + @override | ||
192 | + void layout(Context context, BoxConstraints constraints, | ||
193 | + {bool parentUsesSize = false}) { | ||
194 | + assert(_debugHasNecessaryDirections); | ||
195 | + _hasVisualOverflow = false; | ||
196 | + | ||
197 | + if (children.isEmpty) { | ||
198 | + box = PdfRect.fromPoints(PdfPoint.zero, constraints.smallest); | ||
199 | + return; | ||
200 | + } | ||
201 | + | ||
202 | + BoxConstraints childConstraints; | ||
203 | + double mainAxisLimit = 0.0; | ||
204 | + bool flipMainAxis = false; | ||
205 | + bool flipCrossAxis = false; | ||
206 | + | ||
207 | + switch (direction) { | ||
208 | + case Axis.horizontal: | ||
209 | + childConstraints = BoxConstraints(maxWidth: constraints.maxWidth); | ||
210 | + mainAxisLimit = constraints.maxWidth; | ||
211 | + if (verticalDirection == VerticalDirection.down) { | ||
212 | + flipCrossAxis = true; | ||
213 | + } | ||
214 | + break; | ||
215 | + case Axis.vertical: | ||
216 | + childConstraints = BoxConstraints(maxHeight: constraints.maxHeight); | ||
217 | + mainAxisLimit = constraints.maxHeight; | ||
218 | + if (verticalDirection == VerticalDirection.down) { | ||
219 | + flipMainAxis = true; | ||
220 | + } | ||
221 | + break; | ||
222 | + } | ||
223 | + | ||
224 | + assert(childConstraints != null); | ||
225 | + assert(mainAxisLimit != null); | ||
226 | + | ||
227 | + final double spacing = this.spacing; | ||
228 | + final double runSpacing = this.runSpacing; | ||
229 | + final List<_RunMetrics> runMetrics = <_RunMetrics>[]; | ||
230 | + final Map<Widget, int> childRunMetrics = <Widget, int>{}; | ||
231 | + double mainAxisExtent = 0.0; | ||
232 | + double crossAxisExtent = 0.0; | ||
233 | + double runMainAxisExtent = 0.0; | ||
234 | + double runCrossAxisExtent = 0.0; | ||
235 | + int childCount = 0; | ||
236 | + | ||
237 | + for (Widget child in children) { | ||
238 | + child.layout(context, childConstraints, parentUsesSize: true); | ||
239 | + | ||
240 | + final double childMainAxisExtent = _getMainAxisExtent(child); | ||
241 | + final double childCrossAxisExtent = _getCrossAxisExtent(child); | ||
242 | + | ||
243 | + if (childCount > 0 && | ||
244 | + runMainAxisExtent + spacing + childMainAxisExtent > mainAxisLimit) { | ||
245 | + mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent); | ||
246 | + crossAxisExtent += runCrossAxisExtent; | ||
247 | + if (runMetrics.isNotEmpty) { | ||
248 | + crossAxisExtent += runSpacing; | ||
249 | + } | ||
250 | + runMetrics.add( | ||
251 | + _RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount)); | ||
252 | + runMainAxisExtent = 0.0; | ||
253 | + runCrossAxisExtent = 0.0; | ||
254 | + childCount = 0; | ||
255 | + } | ||
256 | + | ||
257 | + runMainAxisExtent += childMainAxisExtent; | ||
258 | + | ||
259 | + if (childCount > 0) { | ||
260 | + runMainAxisExtent += spacing; | ||
261 | + } | ||
262 | + | ||
263 | + runCrossAxisExtent = math.max(runCrossAxisExtent, childCrossAxisExtent); | ||
264 | + childCount += 1; | ||
265 | + | ||
266 | + childRunMetrics[child] = runMetrics.length; | ||
267 | + } | ||
268 | + | ||
269 | + if (childCount > 0) { | ||
270 | + mainAxisExtent = math.max(mainAxisExtent, runMainAxisExtent); | ||
271 | + crossAxisExtent += runCrossAxisExtent; | ||
272 | + if (runMetrics.isNotEmpty) { | ||
273 | + crossAxisExtent += runSpacing; | ||
274 | + } | ||
275 | + runMetrics | ||
276 | + .add(_RunMetrics(runMainAxisExtent, runCrossAxisExtent, childCount)); | ||
277 | + } | ||
278 | + | ||
279 | + final int runCount = runMetrics.length; | ||
280 | + assert(runCount > 0); | ||
281 | + | ||
282 | + double containerMainAxisExtent = 0.0; | ||
283 | + double containerCrossAxisExtent = 0.0; | ||
284 | + | ||
285 | + switch (direction) { | ||
286 | + case Axis.horizontal: | ||
287 | + box = PdfRect.fromPoints(PdfPoint.zero, | ||
288 | + constraints.constrain(PdfPoint(mainAxisExtent, crossAxisExtent))); | ||
289 | + containerMainAxisExtent = box.width; | ||
290 | + containerCrossAxisExtent = box.height; | ||
291 | + break; | ||
292 | + case Axis.vertical: | ||
293 | + box = PdfRect.fromPoints(PdfPoint.zero, | ||
294 | + constraints.constrain(PdfPoint(crossAxisExtent, mainAxisExtent))); | ||
295 | + containerMainAxisExtent = box.height; | ||
296 | + containerCrossAxisExtent = box.width; | ||
297 | + break; | ||
298 | + } | ||
299 | + | ||
300 | + _hasVisualOverflow = containerMainAxisExtent < mainAxisExtent || | ||
301 | + containerCrossAxisExtent < crossAxisExtent; | ||
302 | + | ||
303 | + final double crossAxisFreeSpace = | ||
304 | + math.max(0.0, containerCrossAxisExtent - crossAxisExtent); | ||
305 | + double runLeadingSpace = 0.0; | ||
306 | + double runBetweenSpace = 0.0; | ||
307 | + | ||
308 | + switch (runAlignment) { | ||
309 | + case WrapAlignment.start: | ||
310 | + break; | ||
311 | + case WrapAlignment.end: | ||
312 | + runLeadingSpace = crossAxisFreeSpace; | ||
313 | + break; | ||
314 | + case WrapAlignment.center: | ||
315 | + runLeadingSpace = crossAxisFreeSpace / 2.0; | ||
316 | + break; | ||
317 | + case WrapAlignment.spaceBetween: | ||
318 | + runBetweenSpace = | ||
319 | + runCount > 1 ? crossAxisFreeSpace / (runCount - 1) : 0.0; | ||
320 | + break; | ||
321 | + case WrapAlignment.spaceAround: | ||
322 | + runBetweenSpace = crossAxisFreeSpace / runCount; | ||
323 | + runLeadingSpace = runBetweenSpace / 2.0; | ||
324 | + break; | ||
325 | + case WrapAlignment.spaceEvenly: | ||
326 | + runBetweenSpace = crossAxisFreeSpace / (runCount + 1); | ||
327 | + runLeadingSpace = runBetweenSpace; | ||
328 | + break; | ||
329 | + } | ||
330 | + | ||
331 | + runBetweenSpace += runSpacing; | ||
332 | + double crossAxisOffset = flipCrossAxis | ||
333 | + ? containerCrossAxisExtent - runLeadingSpace | ||
334 | + : runLeadingSpace; | ||
335 | + | ||
336 | + int currentWidget = 0; | ||
337 | + for (int i = 0; i < runCount; ++i) { | ||
338 | + final _RunMetrics metrics = runMetrics[i]; | ||
339 | + final double runMainAxisExtent = metrics.mainAxisExtent; | ||
340 | + final double runCrossAxisExtent = metrics.crossAxisExtent; | ||
341 | + final int childCount = metrics.childCount; | ||
342 | + | ||
343 | + final double mainAxisFreeSpace = | ||
344 | + math.max(0.0, containerMainAxisExtent - runMainAxisExtent); | ||
345 | + double childLeadingSpace = 0.0; | ||
346 | + double childBetweenSpace = 0.0; | ||
347 | + | ||
348 | + switch (alignment) { | ||
349 | + case WrapAlignment.start: | ||
350 | + break; | ||
351 | + case WrapAlignment.end: | ||
352 | + childLeadingSpace = mainAxisFreeSpace; | ||
353 | + break; | ||
354 | + case WrapAlignment.center: | ||
355 | + childLeadingSpace = mainAxisFreeSpace / 2.0; | ||
356 | + break; | ||
357 | + case WrapAlignment.spaceBetween: | ||
358 | + childBetweenSpace = | ||
359 | + childCount > 1 ? mainAxisFreeSpace / (childCount - 1) : 0.0; | ||
360 | + break; | ||
361 | + case WrapAlignment.spaceAround: | ||
362 | + childBetweenSpace = mainAxisFreeSpace / childCount; | ||
363 | + childLeadingSpace = childBetweenSpace / 2.0; | ||
364 | + break; | ||
365 | + case WrapAlignment.spaceEvenly: | ||
366 | + childBetweenSpace = mainAxisFreeSpace / (childCount + 1); | ||
367 | + childLeadingSpace = childBetweenSpace; | ||
368 | + break; | ||
369 | + } | ||
370 | + | ||
371 | + childBetweenSpace += spacing; | ||
372 | + double childMainPosition = flipMainAxis | ||
373 | + ? containerMainAxisExtent - childLeadingSpace | ||
374 | + : childLeadingSpace; | ||
375 | + | ||
376 | + if (flipCrossAxis) { | ||
377 | + crossAxisOffset -= runCrossAxisExtent; | ||
378 | + } | ||
379 | + | ||
380 | + for (Widget child in children.sublist(currentWidget)) { | ||
381 | + final int runIndex = childRunMetrics[child]; | ||
382 | + if (runIndex != i) { | ||
383 | + break; | ||
384 | + } | ||
385 | + | ||
386 | + currentWidget++; | ||
387 | + final double childMainAxisExtent = _getMainAxisExtent(child); | ||
388 | + final double childCrossAxisExtent = _getCrossAxisExtent(child); | ||
389 | + final double childCrossAxisOffset = _getChildCrossAxisOffset( | ||
390 | + flipCrossAxis, runCrossAxisExtent, childCrossAxisExtent); | ||
391 | + if (flipMainAxis) { | ||
392 | + childMainPosition -= childMainAxisExtent; | ||
393 | + } | ||
394 | + child.box = PdfRect.fromPoints( | ||
395 | + _getOffset( | ||
396 | + childMainPosition, crossAxisOffset + childCrossAxisOffset), | ||
397 | + child.box.size); | ||
398 | + if (flipMainAxis) { | ||
399 | + childMainPosition -= childBetweenSpace; | ||
400 | + } else { | ||
401 | + childMainPosition += childMainAxisExtent + childBetweenSpace; | ||
402 | + } | ||
403 | + } | ||
404 | + | ||
405 | + if (flipCrossAxis) { | ||
406 | + crossAxisOffset -= runBetweenSpace; | ||
407 | + } else { | ||
408 | + crossAxisOffset += runCrossAxisExtent + runBetweenSpace; | ||
409 | + } | ||
410 | + } | ||
411 | + } | ||
412 | + | ||
413 | + @override | ||
414 | + void paint(Context context) { | ||
415 | + super.paint(context); | ||
416 | + | ||
417 | + context.canvas.saveContext(); | ||
418 | + | ||
419 | + if (_hasVisualOverflow) { | ||
420 | + context.canvas | ||
421 | + ..drawRect(box.left, box.bottom, box.width, box.height) | ||
422 | + ..clipPath(); | ||
423 | + } | ||
424 | + | ||
425 | + final Matrix4 mat = Matrix4.identity(); | ||
426 | + mat.translate(box.x, box.y); | ||
427 | + context.canvas.setTransform(mat); | ||
428 | + for (Widget child in children) { | ||
429 | + child.paint(context); | ||
430 | + } | ||
431 | + | ||
432 | + context.canvas.restoreContext(); | ||
433 | + } | ||
434 | +} |
@@ -32,6 +32,7 @@ import 'widget_table_test.dart' as widget_table; | @@ -32,6 +32,7 @@ import 'widget_table_test.dart' as widget_table; | ||
32 | import 'widget_test.dart' as widget; | 32 | import 'widget_test.dart' as widget; |
33 | import 'widget_text_test.dart' as widget_text; | 33 | import 'widget_text_test.dart' as widget_text; |
34 | import 'widget_theme_test.dart' as widget_theme; | 34 | import 'widget_theme_test.dart' as widget_theme; |
35 | +import 'widget_wrap_test.dart' as widget_wrap; | ||
35 | 36 | ||
36 | void main() { | 37 | void main() { |
37 | annotations.main(); | 38 | annotations.main(); |
@@ -49,5 +50,6 @@ void main() { | @@ -49,5 +50,6 @@ void main() { | ||
49 | widget_table.main(); | 50 | widget_table.main(); |
50 | widget_text.main(); | 51 | widget_text.main(); |
51 | widget_theme.main(); | 52 | widget_theme.main(); |
53 | + widget_wrap.main(); | ||
52 | widget.main(); | 54 | widget.main(); |
53 | } | 55 | } |
pdf/test/widget_wrap_test.dart
0 → 100644
1 | +/* | ||
2 | + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com> | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +import 'dart:io'; | ||
18 | +import 'dart:math' as math; | ||
19 | + | ||
20 | +import 'package:test/test.dart'; | ||
21 | +import 'package:pdf/pdf.dart'; | ||
22 | +import 'package:pdf/widgets.dart'; | ||
23 | + | ||
24 | +Document pdf; | ||
25 | + | ||
26 | +void main() { | ||
27 | + setUpAll(() { | ||
28 | + Document.debug = true; | ||
29 | + pdf = Document(); | ||
30 | + }); | ||
31 | + | ||
32 | + test('Wrap Widget Horizontal 1', () { | ||
33 | + final List<Widget> wraps = <Widget>[]; | ||
34 | + for (VerticalDirection direction in VerticalDirection.values) { | ||
35 | + wraps.add(Text('$direction')); | ||
36 | + for (WrapAlignment alignment in WrapAlignment.values) { | ||
37 | + wraps.add(Text('$alignment')); | ||
38 | + wraps.add( | ||
39 | + Wrap( | ||
40 | + direction: Axis.horizontal, | ||
41 | + verticalDirection: direction, | ||
42 | + alignment: alignment, | ||
43 | + children: List<Widget>.generate( | ||
44 | + 40, | ||
45 | + (int n) => Text('${n + 1}'), | ||
46 | + ), | ||
47 | + ), | ||
48 | + ); | ||
49 | + } | ||
50 | + } | ||
51 | + | ||
52 | + pdf.addPage( | ||
53 | + Page( | ||
54 | + pageFormat: const PdfPageFormat(400, 800), | ||
55 | + margin: const EdgeInsets.all(10), | ||
56 | + build: (Context context) => Column( | ||
57 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
58 | + children: wraps, | ||
59 | + ), | ||
60 | + ), | ||
61 | + ); | ||
62 | + }); | ||
63 | + | ||
64 | + test('Wrap Widget Vertical 1', () { | ||
65 | + final List<Widget> wraps = <Widget>[]; | ||
66 | + for (VerticalDirection direction in VerticalDirection.values) { | ||
67 | + wraps.add(Transform.rotateBox(child: Text('$direction'), angle: 1.57)); | ||
68 | + for (WrapAlignment alignment in WrapAlignment.values) { | ||
69 | + wraps.add(Transform.rotateBox(child: Text('$alignment'), angle: 1.57)); | ||
70 | + wraps.add( | ||
71 | + Wrap( | ||
72 | + direction: Axis.vertical, | ||
73 | + verticalDirection: direction, | ||
74 | + alignment: alignment, | ||
75 | + children: List<Widget>.generate( | ||
76 | + 40, | ||
77 | + (int n) => Text('${n + 1}'), | ||
78 | + ), | ||
79 | + ), | ||
80 | + ); | ||
81 | + } | ||
82 | + } | ||
83 | + | ||
84 | + pdf.addPage( | ||
85 | + Page( | ||
86 | + pageFormat: const PdfPageFormat(800, 400), | ||
87 | + margin: const EdgeInsets.all(10), | ||
88 | + build: (Context context) => Row( | ||
89 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
90 | + children: wraps, | ||
91 | + ), | ||
92 | + ), | ||
93 | + ); | ||
94 | + }); | ||
95 | + | ||
96 | + test('Wrap Widget Horizontal 2', () { | ||
97 | + final List<Widget> wraps = <Widget>[]; | ||
98 | + for (WrapCrossAlignment alignment in WrapCrossAlignment.values) { | ||
99 | + final math.Random rnd = math.Random(42); | ||
100 | + wraps.add(Text('$alignment')); | ||
101 | + wraps.add( | ||
102 | + Wrap( | ||
103 | + direction: Axis.horizontal, | ||
104 | + crossAxisAlignment: alignment, | ||
105 | + runSpacing: 20, | ||
106 | + spacing: 20, | ||
107 | + children: List<Widget>.generate( | ||
108 | + 20, | ||
109 | + (int n) => SizedBox( | ||
110 | + width: rnd.nextDouble() * 100, | ||
111 | + height: rnd.nextDouble() * 50, | ||
112 | + child: Placeholder(), | ||
113 | + )), | ||
114 | + ), | ||
115 | + ); | ||
116 | + } | ||
117 | + | ||
118 | + pdf.addPage( | ||
119 | + Page( | ||
120 | + pageFormat: const PdfPageFormat(400, 800), | ||
121 | + margin: const EdgeInsets.all(10), | ||
122 | + build: (Context context) => Column( | ||
123 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
124 | + children: wraps, | ||
125 | + ), | ||
126 | + ), | ||
127 | + ); | ||
128 | + }); | ||
129 | + | ||
130 | + test('Wrap Widget Vertical 2', () { | ||
131 | + final List<Widget> wraps = <Widget>[]; | ||
132 | + for (WrapCrossAlignment alignment in WrapCrossAlignment.values) { | ||
133 | + final math.Random rnd = math.Random(42); | ||
134 | + wraps.add(Transform.rotateBox(child: Text('$alignment'), angle: 1.57)); | ||
135 | + wraps.add( | ||
136 | + Wrap( | ||
137 | + direction: Axis.vertical, | ||
138 | + crossAxisAlignment: alignment, | ||
139 | + runSpacing: 20, | ||
140 | + spacing: 20, | ||
141 | + children: List<Widget>.generate( | ||
142 | + 20, | ||
143 | + (int n) => SizedBox( | ||
144 | + width: rnd.nextDouble() * 50, | ||
145 | + height: rnd.nextDouble() * 100, | ||
146 | + child: Placeholder(), | ||
147 | + )), | ||
148 | + ), | ||
149 | + ); | ||
150 | + } | ||
151 | + | ||
152 | + pdf.addPage( | ||
153 | + Page( | ||
154 | + pageFormat: const PdfPageFormat(800, 400), | ||
155 | + margin: const EdgeInsets.all(10), | ||
156 | + build: (Context context) => Row( | ||
157 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
158 | + children: wraps, | ||
159 | + ), | ||
160 | + ), | ||
161 | + ); | ||
162 | + }); | ||
163 | + | ||
164 | + test('Wrap Widget Horizontal 3', () { | ||
165 | + final List<Widget> wraps = <Widget>[]; | ||
166 | + for (WrapAlignment alignment in WrapAlignment.values) { | ||
167 | + final math.Random rnd = math.Random(42); | ||
168 | + wraps.add(Text('$alignment')); | ||
169 | + wraps.add( | ||
170 | + SizedBox( | ||
171 | + height: 110, | ||
172 | + child: Wrap( | ||
173 | + direction: Axis.horizontal, | ||
174 | + runAlignment: alignment, | ||
175 | + spacing: 20, | ||
176 | + children: List<Widget>.generate( | ||
177 | + 15, | ||
178 | + (int n) => SizedBox( | ||
179 | + width: rnd.nextDouble() * 100, | ||
180 | + height: 20, | ||
181 | + child: Placeholder(), | ||
182 | + )), | ||
183 | + ), | ||
184 | + ), | ||
185 | + ); | ||
186 | + } | ||
187 | + | ||
188 | + pdf.addPage( | ||
189 | + Page( | ||
190 | + pageFormat: const PdfPageFormat(400, 800), | ||
191 | + margin: const EdgeInsets.all(10), | ||
192 | + build: (Context context) => Column( | ||
193 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
194 | + children: wraps, | ||
195 | + ), | ||
196 | + ), | ||
197 | + ); | ||
198 | + }); | ||
199 | + | ||
200 | + test('Wrap Widget Vertical 3', () { | ||
201 | + final List<Widget> wraps = <Widget>[]; | ||
202 | + for (WrapAlignment alignment in WrapAlignment.values) { | ||
203 | + final math.Random rnd = math.Random(42); | ||
204 | + wraps.add(Transform.rotateBox(child: Text('$alignment'), angle: 1.57)); | ||
205 | + wraps.add( | ||
206 | + SizedBox( | ||
207 | + width: 110, | ||
208 | + child: Wrap( | ||
209 | + direction: Axis.vertical, | ||
210 | + runAlignment: alignment, | ||
211 | + spacing: 20, | ||
212 | + children: List<Widget>.generate( | ||
213 | + 15, | ||
214 | + (int n) => SizedBox( | ||
215 | + width: 20, | ||
216 | + height: rnd.nextDouble() * 100, | ||
217 | + child: Placeholder(), | ||
218 | + )), | ||
219 | + ), | ||
220 | + ), | ||
221 | + ); | ||
222 | + } | ||
223 | + | ||
224 | + pdf.addPage( | ||
225 | + Page( | ||
226 | + pageFormat: const PdfPageFormat(800, 400), | ||
227 | + margin: const EdgeInsets.all(10), | ||
228 | + build: (Context context) => Row( | ||
229 | + mainAxisAlignment: MainAxisAlignment.spaceEvenly, | ||
230 | + children: wraps, | ||
231 | + ), | ||
232 | + ), | ||
233 | + ); | ||
234 | + }); | ||
235 | + | ||
236 | + test('Wrap Widget Overlay', () { | ||
237 | + final math.Random rnd = math.Random(42); | ||
238 | + pdf.addPage( | ||
239 | + Page( | ||
240 | + pageFormat: const PdfPageFormat(200, 200), | ||
241 | + margin: const EdgeInsets.all(10), | ||
242 | + build: (Context context) => Wrap( | ||
243 | + spacing: 10, | ||
244 | + runSpacing: 10, | ||
245 | + children: List<Widget>.generate( | ||
246 | + 15, | ||
247 | + (int n) => SizedBox( | ||
248 | + width: rnd.nextDouble() * 100, | ||
249 | + height: rnd.nextDouble() * 100, | ||
250 | + child: Placeholder(), | ||
251 | + )), | ||
252 | + ), | ||
253 | + ), | ||
254 | + ); | ||
255 | + }); | ||
256 | + | ||
257 | + test('Wrap Widget Empty', () { | ||
258 | + pdf.addPage(Page(build: (Context context) => Wrap())); | ||
259 | + }); | ||
260 | + | ||
261 | + tearDownAll(() { | ||
262 | + final File file = File('widgets-wrap.pdf'); | ||
263 | + file.writeAsBytesSync(pdf.save()); | ||
264 | + }); | ||
265 | +} |
-
Please register or login to post a comment