Passthrough SpanningWidget on SingleChildWidget and StatelessWidget
Showing
11 changed files
with
84 additions
and
45 deletions
| @@ -26,8 +26,8 @@ Future<Uint8List> generateDocument( | @@ -26,8 +26,8 @@ Future<Uint8List> generateDocument( | ||
| 26 | final doc = pw.Document(pageMode: PdfPageMode.outlines); | 26 | final doc = pw.Document(pageMode: PdfPageMode.outlines); |
| 27 | 27 | ||
| 28 | doc.addPage(pw.MultiPage( | 28 | doc.addPage(pw.MultiPage( |
| 29 | - pageFormat: | ||
| 30 | - PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), | 29 | + pageFormat: format.copyWith(marginBottom: 1.5 * PdfPageFormat.cm), |
| 30 | + orientation: pw.PageOrientation.portrait, | ||
| 31 | crossAxisAlignment: pw.CrossAxisAlignment.start, | 31 | crossAxisAlignment: pw.CrossAxisAlignment.start, |
| 32 | header: (pw.Context context) { | 32 | header: (pw.Context context) { |
| 33 | if (context.pageNumber == 1) { | 33 | if (context.pageNumber == 1) { |
| @@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
| 10 | - ImageProvider.resolve returns non-null object | 10 | - ImageProvider.resolve returns non-null object |
| 11 | - Fix textScalingFactor with lineSpacing | 11 | - Fix textScalingFactor with lineSpacing |
| 12 | - Implement SpanningWidget on RichText | 12 | - Implement SpanningWidget on RichText |
| 13 | +- Passthrough SpanningWidget on SingleChildWidget and StatelessWidget | ||
| 13 | 14 | ||
| 14 | ## 3.2.0 | 15 | ## 3.2.0 |
| 15 | 16 |
| @@ -133,12 +133,13 @@ class Header extends StatelessWidget { | @@ -133,12 +133,13 @@ class Header extends StatelessWidget { | ||
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | class Paragraph extends StatelessWidget { | 135 | class Paragraph extends StatelessWidget { |
| 136 | - Paragraph( | ||
| 137 | - {this.text, | ||
| 138 | - this.textAlign = TextAlign.justify, | ||
| 139 | - this.style, | ||
| 140 | - this.margin = const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm), | ||
| 141 | - this.padding}); | 136 | + Paragraph({ |
| 137 | + this.text, | ||
| 138 | + this.textAlign = TextAlign.justify, | ||
| 139 | + this.style, | ||
| 140 | + this.margin = const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm), | ||
| 141 | + this.padding, | ||
| 142 | + }); | ||
| 142 | 143 | ||
| 143 | final String? text; | 144 | final String? text; |
| 144 | 145 | ||
| @@ -159,6 +160,7 @@ class Paragraph extends StatelessWidget { | @@ -159,6 +160,7 @@ class Paragraph extends StatelessWidget { | ||
| 159 | text!, | 160 | text!, |
| 160 | textAlign: textAlign, | 161 | textAlign: textAlign, |
| 161 | style: style ?? Theme.of(context).paragraphStyle, | 162 | style: style ?? Theme.of(context).paragraphStyle, |
| 163 | + overflow: TextOverflow.span, | ||
| 162 | ), | 164 | ), |
| 163 | ); | 165 | ); |
| 164 | } | 166 | } |
| @@ -81,7 +81,7 @@ class _FlexContext extends WidgetContext { | @@ -81,7 +81,7 @@ class _FlexContext extends WidgetContext { | ||
| 81 | String toString() => '$runtimeType first:$firstChild last:$lastChild'; | 81 | String toString() => '$runtimeType first:$firstChild last:$lastChild'; |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | -class Flex extends MultiChildWidget implements SpanningWidget { | 84 | +class Flex extends MultiChildWidget with SpanningWidget { |
| 85 | Flex({ | 85 | Flex({ |
| 86 | required this.direction, | 86 | required this.direction, |
| 87 | this.mainAxisAlignment = MainAxisAlignment.start, | 87 | this.mainAxisAlignment = MainAxisAlignment.start, |
| @@ -53,7 +53,7 @@ class _GridViewContext extends WidgetContext { | @@ -53,7 +53,7 @@ class _GridViewContext extends WidgetContext { | ||
| 53 | '$runtimeType first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis'; | 53 | '$runtimeType first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis'; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | -class GridView extends MultiChildWidget implements SpanningWidget { | 56 | +class GridView extends MultiChildWidget with SpanningWidget { |
| 57 | GridView( | 57 | GridView( |
| 58 | {this.direction = Axis.vertical, | 58 | {this.direction = Axis.vertical, |
| 59 | this.padding = EdgeInsets.zero, | 59 | this.padding = EdgeInsets.zero, |
| @@ -37,7 +37,7 @@ abstract class WidgetContext { | @@ -37,7 +37,7 @@ abstract class WidgetContext { | ||
| 37 | void apply(covariant WidgetContext other); | 37 | void apply(covariant WidgetContext other); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | -abstract class SpanningWidget extends Widget { | 40 | +mixin SpanningWidget on Widget { |
| 41 | bool get canSpan; | 41 | bool get canSpan; |
| 42 | 42 | ||
| 43 | bool get hasMoreWidgets; | 43 | bool get hasMoreWidgets; |
| @@ -46,7 +46,7 @@ abstract class SpanningWidget extends Widget { | @@ -46,7 +46,7 @@ abstract class SpanningWidget extends Widget { | ||
| 46 | @protected | 46 | @protected |
| 47 | WidgetContext saveContext(); | 47 | WidgetContext saveContext(); |
| 48 | 48 | ||
| 49 | - /// Aplpy the context for next layout | 49 | + /// Apply the context for next layout |
| 50 | @protected | 50 | @protected |
| 51 | void restoreContext(covariant WidgetContext context); | 51 | void restoreContext(covariant WidgetContext context); |
| 52 | } | 52 | } |
| @@ -230,10 +230,6 @@ class MultiPage extends Page { | @@ -230,10 +230,6 @@ class MultiPage extends Page { | ||
| 230 | 230 | ||
| 231 | while (_index < children.length) { | 231 | while (_index < children.length) { |
| 232 | final child = children[_index]; | 232 | final child = children[_index]; |
| 233 | - var canSpan = false; | ||
| 234 | - if (child is SpanningWidget) { | ||
| 235 | - canSpan = child.canSpan; | ||
| 236 | - } | ||
| 237 | 233 | ||
| 238 | assert(() { | 234 | assert(() { |
| 239 | // Detect too big widgets | 235 | // Detect too big widgets |
| @@ -292,7 +288,7 @@ class MultiPage extends Page { | @@ -292,7 +288,7 @@ class MultiPage extends Page { | ||
| 292 | } | 288 | } |
| 293 | 289 | ||
| 294 | // If we are processing a multi-page widget, we restore its context | 290 | // If we are processing a multi-page widget, we restore its context |
| 295 | - if (widgetContext != null && canSpan && child is SpanningWidget) { | 291 | + if (widgetContext != null && child is SpanningWidget) { |
| 296 | child.restoreContext(widgetContext); | 292 | child.restoreContext(widgetContext); |
| 297 | widgetContext = null; | 293 | widgetContext = null; |
| 298 | } | 294 | } |
| @@ -300,6 +296,8 @@ class MultiPage extends Page { | @@ -300,6 +296,8 @@ class MultiPage extends Page { | ||
| 300 | child.layout(context, constraints, parentUsesSize: false); | 296 | child.layout(context, constraints, parentUsesSize: false); |
| 301 | assert(child.box != null); | 297 | assert(child.box != null); |
| 302 | 298 | ||
| 299 | + final canSpan = child is SpanningWidget && child.canSpan; | ||
| 300 | + | ||
| 303 | // What to do if the widget is too big for the page? | 301 | // What to do if the widget is too big for the page? |
| 304 | if (offsetStart! - child.box!.height < offsetEnd) { | 302 | if (offsetStart! - child.box!.height < offsetEnd) { |
| 305 | // If it is not a multi-page widget and its height | 303 | // If it is not a multi-page widget and its height |
| @@ -475,7 +473,8 @@ class MultiPage extends Page { | @@ -475,7 +473,8 @@ class MultiPage extends Page { | ||
| 475 | final flex = child is Flexible ? child.flex : 0; | 473 | final flex = child is Flexible ? child.flex : 0; |
| 476 | final fit = child is Flexible ? child.fit : FlexFit.loose; | 474 | final fit = child is Flexible ? child.fit : FlexFit.loose; |
| 477 | if (flex > 0) { | 475 | if (flex > 0) { |
| 478 | - assert(child is! SpanningWidget); | 476 | + assert(child is! SpanningWidget || child.canSpan == false, |
| 477 | + 'Cannot have a spanning widget flexible'); | ||
| 479 | final maxChildExtent = child == lastFlexChild | 478 | final maxChildExtent = child == lastFlexChild |
| 480 | ? (freeSpace - allocatedFlexSpace) | 479 | ? (freeSpace - allocatedFlexSpace) |
| 481 | : spacePerFlex * flex; | 480 | : spacePerFlex * flex; |
| @@ -24,7 +24,7 @@ import 'geometry.dart'; | @@ -24,7 +24,7 @@ import 'geometry.dart'; | ||
| 24 | import 'multi_page.dart'; | 24 | import 'multi_page.dart'; |
| 25 | import 'widget.dart'; | 25 | import 'widget.dart'; |
| 26 | 26 | ||
| 27 | -class Partition implements SpanningWidget { | 27 | +class Partition extends Widget with SpanningWidget { |
| 28 | Partition({ | 28 | Partition({ |
| 29 | required this.child, | 29 | required this.child, |
| 30 | this.width, | 30 | this.width, |
| @@ -59,6 +59,7 @@ class Partition implements SpanningWidget { | @@ -59,6 +59,7 @@ class Partition implements SpanningWidget { | ||
| 59 | 59 | ||
| 60 | @override | 60 | @override |
| 61 | void paint(Context context) { | 61 | void paint(Context context) { |
| 62 | + super.paint(context); | ||
| 62 | child.paint(context); | 63 | child.paint(context); |
| 63 | } | 64 | } |
| 64 | 65 | ||
| @@ -102,7 +103,7 @@ class _PartitionsContext extends WidgetContext { | @@ -102,7 +103,7 @@ class _PartitionsContext extends WidgetContext { | ||
| 102 | } | 103 | } |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 105 | -class Partitions extends Widget implements SpanningWidget { | 106 | +class Partitions extends Widget with SpanningWidget { |
| 106 | Partitions({ | 107 | Partitions({ |
| 107 | required this.children, | 108 | required this.children, |
| 108 | this.mainAxisSize = MainAxisSize.max, | 109 | this.mainAxisSize = MainAxisSize.max, |
| @@ -236,7 +236,7 @@ typedef OnCellDecoration = BoxDecoration Function( | @@ -236,7 +236,7 @@ typedef OnCellDecoration = BoxDecoration Function( | ||
| 236 | int index, dynamic data, int rowNum); | 236 | int index, dynamic data, int rowNum); |
| 237 | 237 | ||
| 238 | /// A widget that uses the table layout algorithm for its children. | 238 | /// A widget that uses the table layout algorithm for its children. |
| 239 | -class Table extends Widget implements SpanningWidget { | 239 | +class Table extends Widget with SpanningWidget { |
| 240 | Table({ | 240 | Table({ |
| 241 | this.children = const <TableRow>[], | 241 | this.children = const <TableRow>[], |
| 242 | this.border, | 242 | this.border, |
| @@ -575,7 +575,7 @@ class _RichTextContext extends WidgetContext { | @@ -575,7 +575,7 @@ class _RichTextContext extends WidgetContext { | ||
| 575 | '$runtimeType Offset: $startOffset -> $endOffset Span: $spanStart -> $spanEnd'; | 575 | '$runtimeType Offset: $startOffset -> $endOffset Span: $spanStart -> $spanEnd'; |
| 576 | } | 576 | } |
| 577 | 577 | ||
| 578 | -class RichText extends Widget implements SpanningWidget { | 578 | +class RichText extends Widget with SpanningWidget { |
| 579 | RichText({ | 579 | RichText({ |
| 580 | required this.text, | 580 | required this.text, |
| 581 | this.textAlign, | 581 | this.textAlign, |
| @@ -19,6 +19,7 @@ import 'dart:math' as math; | @@ -19,6 +19,7 @@ import 'dart:math' as math; | ||
| 19 | 19 | ||
| 20 | import 'package:meta/meta.dart'; | 20 | import 'package:meta/meta.dart'; |
| 21 | import 'package:pdf/pdf.dart'; | 21 | import 'package:pdf/pdf.dart'; |
| 22 | +import 'package:pdf/widgets.dart'; | ||
| 22 | import 'package:vector_math/vector_math_64.dart'; | 23 | import 'package:vector_math/vector_math_64.dart'; |
| 23 | 24 | ||
| 24 | import 'document.dart'; | 25 | import 'document.dart'; |
| @@ -210,7 +211,7 @@ abstract class Widget { | @@ -210,7 +211,7 @@ abstract class Widget { | ||
| 210 | } | 211 | } |
| 211 | } | 212 | } |
| 212 | 213 | ||
| 213 | -abstract class StatelessWidget extends Widget { | 214 | +abstract class StatelessWidget extends Widget with SpanningWidget { |
| 214 | StatelessWidget() : super(); | 215 | StatelessWidget() : super(); |
| 215 | 216 | ||
| 216 | Widget? _child; | 217 | Widget? _child; |
| @@ -246,9 +247,33 @@ abstract class StatelessWidget extends Widget { | @@ -246,9 +247,33 @@ abstract class StatelessWidget extends Widget { | ||
| 246 | 247 | ||
| 247 | @protected | 248 | @protected |
| 248 | Widget build(Context context); | 249 | Widget build(Context context); |
| 250 | + | ||
| 251 | + @override | ||
| 252 | + bool get canSpan => | ||
| 253 | + _child is SpanningWidget && (_child as SpanningWidget).canSpan; | ||
| 254 | + | ||
| 255 | + @override | ||
| 256 | + bool get hasMoreWidgets => | ||
| 257 | + _child is SpanningWidget && (_child as SpanningWidget).hasMoreWidgets; | ||
| 258 | + | ||
| 259 | + @override | ||
| 260 | + void restoreContext(covariant WidgetContext context) { | ||
| 261 | + if (_child is SpanningWidget) { | ||
| 262 | + (_child as SpanningWidget).restoreContext(context); | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + @override | ||
| 267 | + WidgetContext saveContext() { | ||
| 268 | + if (_child is SpanningWidget) { | ||
| 269 | + return (_child as SpanningWidget).saveContext(); | ||
| 270 | + } | ||
| 271 | + | ||
| 272 | + throw UnimplementedError(); | ||
| 273 | + } | ||
| 249 | } | 274 | } |
| 250 | 275 | ||
| 251 | -abstract class SingleChildWidget extends Widget { | 276 | +abstract class SingleChildWidget extends Widget with SpanningWidget { |
| 252 | SingleChildWidget({this.child}) : super(); | 277 | SingleChildWidget({this.child}) : super(); |
| 253 | 278 | ||
| 254 | final Widget? child; | 279 | final Widget? child; |
| @@ -277,6 +302,30 @@ abstract class SingleChildWidget extends Widget { | @@ -277,6 +302,30 @@ abstract class SingleChildWidget extends Widget { | ||
| 277 | context.canvas.restoreContext(); | 302 | context.canvas.restoreContext(); |
| 278 | } | 303 | } |
| 279 | } | 304 | } |
| 305 | + | ||
| 306 | + @override | ||
| 307 | + bool get canSpan => | ||
| 308 | + child is SpanningWidget && (child as SpanningWidget).canSpan; | ||
| 309 | + | ||
| 310 | + @override | ||
| 311 | + bool get hasMoreWidgets => | ||
| 312 | + child is SpanningWidget && (child as SpanningWidget).hasMoreWidgets; | ||
| 313 | + | ||
| 314 | + @override | ||
| 315 | + void restoreContext(covariant WidgetContext context) { | ||
| 316 | + if (child is SpanningWidget) { | ||
| 317 | + (child as SpanningWidget).restoreContext(context); | ||
| 318 | + } | ||
| 319 | + } | ||
| 320 | + | ||
| 321 | + @override | ||
| 322 | + WidgetContext saveContext() { | ||
| 323 | + if (child is SpanningWidget) { | ||
| 324 | + return (child as SpanningWidget).saveContext(); | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + throw UnimplementedError(); | ||
| 328 | + } | ||
| 280 | } | 329 | } |
| 281 | 330 | ||
| 282 | abstract class MultiChildWidget extends Widget { | 331 | abstract class MultiChildWidget extends Widget { |
| @@ -285,8 +334,8 @@ abstract class MultiChildWidget extends Widget { | @@ -285,8 +334,8 @@ abstract class MultiChildWidget extends Widget { | ||
| 285 | final List<Widget> children; | 334 | final List<Widget> children; |
| 286 | } | 335 | } |
| 287 | 336 | ||
| 288 | -class InheritedWidget extends Widget { | ||
| 289 | - InheritedWidget({this.build, this.inherited}); | 337 | +class InheritedWidget extends SingleChildWidget { |
| 338 | + InheritedWidget({this.build, this.inherited}) : super(); | ||
| 290 | 339 | ||
| 291 | final BuildCallback? build; | 340 | final BuildCallback? build; |
| 292 | 341 | ||
| @@ -294,6 +343,9 @@ class InheritedWidget extends Widget { | @@ -294,6 +343,9 @@ class InheritedWidget extends Widget { | ||
| 294 | 343 | ||
| 295 | Context? _context; | 344 | Context? _context; |
| 296 | 345 | ||
| 346 | + @override | ||
| 347 | + Widget? get child => _child; | ||
| 348 | + | ||
| 297 | Widget? _child; | 349 | Widget? _child; |
| 298 | 350 | ||
| 299 | @override | 351 | @override |
| @@ -301,29 +353,13 @@ class InheritedWidget extends Widget { | @@ -301,29 +353,13 @@ class InheritedWidget extends Widget { | ||
| 301 | {bool parentUsesSize = false}) { | 353 | {bool parentUsesSize = false}) { |
| 302 | _context = inherited != null ? context.inheritFrom(inherited!) : context; | 354 | _context = inherited != null ? context.inheritFrom(inherited!) : context; |
| 303 | _child = build!(_context!); | 355 | _child = build!(_context!); |
| 304 | - | ||
| 305 | - if (_child != null) { | ||
| 306 | - _child!.layout(_context!, constraints, parentUsesSize: parentUsesSize); | ||
| 307 | - assert(_child!.box != null); | ||
| 308 | - box = _child!.box; | ||
| 309 | - } else { | ||
| 310 | - box = PdfRect.fromPoints(PdfPoint.zero, constraints.smallest); | ||
| 311 | - } | 356 | + super.layout(_context!, constraints); |
| 312 | } | 357 | } |
| 313 | 358 | ||
| 314 | @override | 359 | @override |
| 315 | void paint(Context context) { | 360 | void paint(Context context) { |
| 316 | assert(_context != null); | 361 | assert(_context != null); |
| 317 | super.paint(_context!); | 362 | super.paint(_context!); |
| 318 | - | ||
| 319 | - if (_child != null) { | ||
| 320 | - final mat = Matrix4.identity(); | ||
| 321 | - mat.translate(box!.x, box!.y); | ||
| 322 | - context.canvas | ||
| 323 | - ..saveContext() | ||
| 324 | - ..setTransform(mat); | ||
| 325 | - _child!.paint(_context!); | ||
| 326 | - context.canvas.restoreContext(); | ||
| 327 | - } | 363 | + paintChild(_context!); |
| 328 | } | 364 | } |
| 329 | } | 365 | } |
| @@ -67,7 +67,7 @@ class _WrapContext extends WidgetContext { | @@ -67,7 +67,7 @@ class _WrapContext extends WidgetContext { | ||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | /// A widget that displays its children in multiple horizontal or vertical runs. | 69 | /// A widget that displays its children in multiple horizontal or vertical runs. |
| 70 | -class Wrap extends MultiChildWidget implements SpanningWidget { | 70 | +class Wrap extends MultiChildWidget with SpanningWidget { |
| 71 | /// Creates a wrap layout. | 71 | /// Creates a wrap layout. |
| 72 | 72 | ||
| 73 | Wrap({ | 73 | Wrap({ |
-
Please register or login to post a comment