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