Committed by
David PHAM-VAN
support multi page slots alignments
Showing
3 changed files
with
112 additions
and
45 deletions
@@ -188,28 +188,18 @@ class MultiPage extends Page { | @@ -188,28 +188,18 @@ class MultiPage extends Page { | ||
188 | final _margin = resolvedMargin!; | 188 | final _margin = resolvedMargin!; |
189 | context.canvas | 189 | context.canvas |
190 | ..saveContext() | 190 | ..saveContext() |
191 | - ..setTransform(Matrix4.identity() | 191 | + ..setTransform( |
192 | + Matrix4.identity() | ||
192 | ..rotateZ(-math.pi / 2) | 193 | ..rotateZ(-math.pi / 2) |
193 | ..translate( | 194 | ..translate( |
194 | x - pageHeight + _margin.top - _margin.left, | 195 | x - pageHeight + _margin.top - _margin.left, |
195 | y + _margin.left - _margin.bottom, | 196 | y + _margin.left - _margin.bottom, |
196 | - )); | ||
197 | - | ||
198 | - final availableWidth = pageHeight - resolvedMargin!.vertical; | ||
199 | - if (pageTheme.textDirection == TextDirection.rtl) { | ||
200 | - child.box = child.box!.copyWith( | ||
201 | - x: (availableWidth - child.box!.width) + child.box!.x, | 197 | + ), |
202 | ); | 198 | ); |
203 | - } | ||
204 | child.paint(context); | 199 | child.paint(context); |
205 | context.canvas.restoreContext(); | 200 | context.canvas.restoreContext(); |
206 | } else { | 201 | } else { |
207 | - var childXPos = x; | ||
208 | - if (pageTheme.textDirection == TextDirection.rtl) { | ||
209 | - final availableWidth = pageFormat.width - resolvedMargin!.horizontal; | ||
210 | - childXPos = (availableWidth - child.box!.width) + x; | ||
211 | - } | ||
212 | - child.box = child.box!.copyWith(x: childXPos, y: y); | 202 | + child.box = child.box!.copyWith(x: x, y: y); |
213 | child.paint(context); | 203 | child.paint(context); |
214 | } | 204 | } |
215 | } | 205 | } |
@@ -384,7 +374,7 @@ class MultiPage extends Page { | @@ -384,7 +374,7 @@ class MultiPage extends Page { | ||
384 | final pageHeightMargin = _mustRotate ? _margin.horizontal : _margin.vertical; | 374 | final pageHeightMargin = _mustRotate ? _margin.horizontal : _margin.vertical; |
385 | final pageWidthMargin = _mustRotate ? _margin.vertical : _margin.horizontal; | 375 | final pageWidthMargin = _mustRotate ? _margin.vertical : _margin.horizontal; |
386 | final availableWidth = pageWidth - pageWidthMargin; | 376 | final availableWidth = pageWidth - pageWidthMargin; |
387 | - | 377 | + final isRTL = pageTheme.textDirection == TextDirection.rtl; |
388 | for (final page in _pages) { | 378 | for (final page in _pages) { |
389 | var offsetStart = pageHeight - (_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top); | 379 | var offsetStart = pageHeight - (_mustRotate ? pageHeightMargin - _margin.bottom : _margin.top); |
390 | var offsetEnd = _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom; | 380 | var offsetEnd = _mustRotate ? pageHeightMargin - _margin.left : _margin.bottom; |
@@ -394,7 +384,8 @@ class MultiPage extends Page { | @@ -394,7 +384,8 @@ class MultiPage extends Page { | ||
394 | 384 | ||
395 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); | 385 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); |
396 | assert(child.box != null); | 386 | assert(child.box != null); |
397 | - _paintChild(page.context, child, _margin.left, _margin.bottom, pageFormat.height); | 387 | + final xPos = isRTL ? _margin.left + (availableWidth - child.box!.width) : _margin.left; |
388 | + _paintChild(page.context, child, xPos, _margin.bottom, pageFormat.height); | ||
398 | } | 389 | } |
399 | 390 | ||
400 | var totalFlex = 0; | 391 | var totalFlex = 0; |
@@ -419,21 +410,20 @@ class MultiPage extends Page { | @@ -419,21 +410,20 @@ class MultiPage extends Page { | ||
419 | 410 | ||
420 | if (header != null) { | 411 | if (header != null) { |
421 | final headerWidget = header!(page.context); | 412 | final headerWidget = header!(page.context); |
422 | - | ||
423 | headerWidget.layout(page.context, page.constraints, parentUsesSize: false); | 413 | headerWidget.layout(page.context, page.constraints, parentUsesSize: false); |
424 | assert(headerWidget.box != null); | 414 | assert(headerWidget.box != null); |
425 | offsetStart -= headerWidget.box!.height; | 415 | offsetStart -= headerWidget.box!.height; |
426 | - _paintChild( | ||
427 | - page.context, headerWidget, _margin.left, page.offsetStart! - headerWidget.box!.height, pageFormat.height); | 416 | + final xPos = isRTL ? _margin.left + (availableWidth - headerWidget.box!.width) : _margin.left; |
417 | + _paintChild(page.context, headerWidget, xPos, page.offsetStart! - headerWidget.box!.height, pageFormat.height); | ||
428 | } | 418 | } |
429 | 419 | ||
430 | if (footer != null) { | 420 | if (footer != null) { |
431 | final footerWidget = footer!(page.context); | 421 | final footerWidget = footer!(page.context); |
432 | - | ||
433 | footerWidget.layout(page.context, page.constraints, parentUsesSize: false); | 422 | footerWidget.layout(page.context, page.constraints, parentUsesSize: false); |
434 | assert(footerWidget.box != null); | 423 | assert(footerWidget.box != null); |
424 | + final xPos = isRTL ? _margin.left + (availableWidth - footerWidget.box!.width) : _margin.left; | ||
435 | offsetEnd += footerWidget.box!.height; | 425 | offsetEnd += footerWidget.box!.height; |
436 | - _paintChild(page.context, footerWidget, _margin.left, _margin.bottom, pageFormat.height); | 426 | + _paintChild(page.context, footerWidget, xPos, _margin.bottom, pageFormat.height); |
437 | } | 427 | } |
438 | 428 | ||
439 | final freeSpace = math.max(0.0, offsetStart - offsetEnd - allocatedSize); | 429 | final freeSpace = math.max(0.0, offsetStart - offsetEnd - allocatedSize); |
@@ -508,24 +498,29 @@ class MultiPage extends Page { | @@ -508,24 +498,29 @@ class MultiPage extends Page { | ||
508 | allocatedFlexSpace += maxChildExtent; | 498 | allocatedFlexSpace += maxChildExtent; |
509 | } | 499 | } |
510 | } | 500 | } |
511 | - | ||
512 | var pos = offsetStart - leadingSpace; | 501 | var pos = offsetStart - leadingSpace; |
513 | for (final widget in page.widgets) { | 502 | for (final widget in page.widgets) { |
514 | pos -= widget.child.box!.height; | 503 | pos -= widget.child.box!.height; |
515 | late double x; | 504 | late double x; |
516 | switch (crossAxisAlignment) { | 505 | switch (crossAxisAlignment) { |
506 | + case CrossAxisAlignment.stretch: | ||
517 | case CrossAxisAlignment.start: | 507 | case CrossAxisAlignment.start: |
508 | + if (isRTL) { | ||
509 | + x = availableWidth - widget.child.box!.width; | ||
510 | + } else { | ||
518 | x = 0; | 511 | x = 0; |
512 | + } | ||
519 | break; | 513 | break; |
520 | case CrossAxisAlignment.end: | 514 | case CrossAxisAlignment.end: |
515 | + if (isRTL) { | ||
516 | + x = 0; | ||
517 | + } else { | ||
521 | x = availableWidth - widget.child.box!.width; | 518 | x = availableWidth - widget.child.box!.width; |
519 | + } | ||
522 | break; | 520 | break; |
523 | case CrossAxisAlignment.center: | 521 | case CrossAxisAlignment.center: |
524 | x = availableWidth / 2 - widget.child.box!.width / 2; | 522 | x = availableWidth / 2 - widget.child.box!.width / 2; |
525 | break; | 523 | break; |
526 | - case CrossAxisAlignment.stretch: | ||
527 | - x = 0; | ||
528 | - break; | ||
529 | } | 524 | } |
530 | final child = widget.child; | 525 | final child = widget.child; |
531 | if (child is SpanningWidget && child.canSpan) { | 526 | if (child is SpanningWidget && child.canSpan) { |
@@ -540,7 +535,8 @@ class MultiPage extends Page { | @@ -540,7 +535,8 @@ class MultiPage extends Page { | ||
540 | 535 | ||
541 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); | 536 | child.layout(page.context, page.fullConstraints, parentUsesSize: false); |
542 | assert(child.box != null); | 537 | assert(child.box != null); |
543 | - _paintChild(page.context, child, _margin.left, _margin.bottom, pageFormat.height); | 538 | + final xPos = isRTL ? _margin.left + (availableWidth - child.box!.width) : _margin.left; |
539 | + _paintChild(page.context, child, xPos, _margin.bottom, pageFormat.height); | ||
544 | } | 540 | } |
545 | } | 541 | } |
546 | } | 542 | } |
@@ -566,7 +566,7 @@ class _Line { | @@ -566,7 +566,7 @@ class _Line { | ||
566 | delta = isRTL ? wordsWidth : 0; | 566 | delta = isRTL ? wordsWidth : 0; |
567 | break; | 567 | break; |
568 | case TextAlign.right: | 568 | case TextAlign.right: |
569 | - delta = totalWidth - wordsWidth; | 569 | + delta = isRTL ? totalWidth: totalWidth - wordsWidth; |
570 | break; | 570 | break; |
571 | case TextAlign.start: | 571 | case TextAlign.start: |
572 | delta = isRTL ? totalWidth : 0; | 572 | delta = isRTL ? totalWidth : 0; |
@@ -576,6 +576,9 @@ class _Line { | @@ -576,6 +576,9 @@ class _Line { | ||
576 | break; | 576 | break; |
577 | case TextAlign.center: | 577 | case TextAlign.center: |
578 | delta = (totalWidth - wordsWidth) / 2.0; | 578 | delta = (totalWidth - wordsWidth) / 2.0; |
579 | + if(isRTL) { | ||
580 | + delta += wordsWidth; | ||
581 | + } | ||
579 | break; | 582 | break; |
580 | case TextAlign.justify: | 583 | case TextAlign.justify: |
581 | delta = isRTL ? totalWidth : 0; | 584 | delta = isRTL ? totalWidth : 0; |
@@ -15,7 +15,6 @@ | @@ -15,7 +15,6 @@ | ||
15 | */ | 15 | */ |
16 | 16 | ||
17 | import 'dart:io'; | 17 | import 'dart:io'; |
18 | -import 'dart:typed_data'; | ||
19 | 18 | ||
20 | import 'package:pdf/pdf.dart'; | 19 | import 'package:pdf/pdf.dart'; |
21 | import 'package:pdf/widgets.dart'; | 20 | import 'package:pdf/widgets.dart'; |
@@ -42,16 +41,38 @@ final _yellowBox = Container( | @@ -42,16 +41,38 @@ final _yellowBox = Container( | ||
42 | ); | 41 | ); |
43 | 42 | ||
44 | void main() { | 43 | void main() { |
45 | - late final arabicFont; | ||
46 | setUpAll(() { | 44 | setUpAll(() { |
47 | Document.debug = true; | 45 | Document.debug = true; |
48 | pdf = Document(); | 46 | pdf = Document(); |
49 | - final fontData = File('test/fonts/cairo.ttf').readAsBytesSync(); | ||
50 | - // final fontData = File('test/fonts/hacen_tunisia.ttf').readAsBytesSync(); | ||
51 | - arabicFont = Font.ttf(fontData.buffer.asByteData()); | ||
52 | }); | 47 | }); |
53 | 48 | ||
54 | - test('Should render Text aligned right', () { | 49 | + test('Should render a blue box followed by a red box ordered RTL aligned right', () { |
50 | + pdf.addPage( | ||
51 | + Page( | ||
52 | + textDirection: TextDirection.rtl, | ||
53 | + pageFormat: const PdfPageFormat(150, 50), | ||
54 | + build: (Context context) => TestAnnotation( | ||
55 | + anno: 'RTL Row', | ||
56 | + child: Row( | ||
57 | + children: [_blueBox, _redBox], | ||
58 | + ), | ||
59 | + ), | ||
60 | + ), | ||
61 | + ); | ||
62 | + }); | ||
63 | + | ||
64 | + test('RTL Text', () { | ||
65 | + pdf.addPage( | ||
66 | + Page( | ||
67 | + textDirection: TextDirection.rtl, | ||
68 | + pageFormat: const PdfPageFormat(150, 50), | ||
69 | + build: (Context context) => Text( | ||
70 | + 'RTL Text', | ||
71 | + ), | ||
72 | + ), | ||
73 | + ); | ||
74 | + }); | ||
75 | + test('RTL Text TextAlign.end', () { | ||
55 | pdf.addPage( | 76 | pdf.addPage( |
56 | Page( | 77 | Page( |
57 | textDirection: TextDirection.rtl, | 78 | textDirection: TextDirection.rtl, |
@@ -59,23 +80,67 @@ void main() { | @@ -59,23 +80,67 @@ void main() { | ||
59 | build: (Context context) => SizedBox( | 80 | build: (Context context) => SizedBox( |
60 | width: 150, | 81 | width: 150, |
61 | child: Text( | 82 | child: Text( |
62 | - 'مرحبا بالعالم', | ||
63 | - style: TextStyle(font: arabicFont), | 83 | + 'RTL Text : TextAlign.end', |
84 | + textAlign: TextAlign.end, | ||
64 | ), | 85 | ), |
65 | ), | 86 | ), |
66 | ), | 87 | ), |
67 | ); | 88 | ); |
68 | }); | 89 | }); |
69 | 90 | ||
70 | - test('Should render a blue box followed by a red box ordered RTL aligned right', () { | 91 | + test('RTL Text TextAlign.left', () { |
71 | pdf.addPage( | 92 | pdf.addPage( |
72 | Page( | 93 | Page( |
73 | textDirection: TextDirection.rtl, | 94 | textDirection: TextDirection.rtl, |
74 | pageFormat: const PdfPageFormat(150, 50), | 95 | pageFormat: const PdfPageFormat(150, 50), |
75 | - build: (Context context) => TestAnnotation( | ||
76 | - anno: 'RTL Row', | ||
77 | - child: Row( | ||
78 | - children: [_blueBox, _redBox], | 96 | + build: (Context context) => SizedBox( |
97 | + width: 150, | ||
98 | + child: Text( | ||
99 | + 'RTL Text : TextAlign.left', | ||
100 | + textAlign: TextAlign.left, | ||
101 | + ), | ||
102 | + ), | ||
103 | + ), | ||
104 | + ); | ||
105 | + }); | ||
106 | + | ||
107 | + test('LTR Text', () { | ||
108 | + pdf.addPage( | ||
109 | + Page( | ||
110 | + textDirection: TextDirection.ltr, | ||
111 | + pageFormat: const PdfPageFormat(150, 50), | ||
112 | + build: (Context context) => Text( | ||
113 | + 'LTR Text', | ||
114 | + ), | ||
115 | + ), | ||
116 | + ); | ||
117 | + }); | ||
118 | + test('LTR Text TextAlign.end', () { | ||
119 | + pdf.addPage( | ||
120 | + Page( | ||
121 | + textDirection: TextDirection.ltr, | ||
122 | + pageFormat: const PdfPageFormat(150, 50), | ||
123 | + build: (Context context) => SizedBox( | ||
124 | + width: 150, | ||
125 | + child: Text( | ||
126 | + 'RTL Text : TextAlign.end', | ||
127 | + textAlign: TextAlign.end, | ||
128 | + ), | ||
129 | + ), | ||
130 | + ), | ||
131 | + ); | ||
132 | + }); | ||
133 | + | ||
134 | + test('LTR Text TextAlign.right', () { | ||
135 | + pdf.addPage( | ||
136 | + Page( | ||
137 | + textDirection: TextDirection.ltr, | ||
138 | + pageFormat: const PdfPageFormat(150, 50), | ||
139 | + build: (Context context) => SizedBox( | ||
140 | + width: 150, | ||
141 | + child: Text( | ||
142 | + 'LTR Text : TextAlign.right', | ||
143 | + textAlign: TextAlign.right, | ||
79 | ), | 144 | ), |
80 | ), | 145 | ), |
81 | ), | 146 | ), |
@@ -286,10 +351,12 @@ void main() { | @@ -286,10 +351,12 @@ void main() { | ||
286 | pageFormat: const PdfPageFormat(150, 150), | 351 | pageFormat: const PdfPageFormat(150, 150), |
287 | build: (Context context) { | 352 | build: (Context context) { |
288 | return [ | 353 | return [ |
289 | - ListView(children: [ | ||
290 | - Text('RTL MultiPage'), | 354 | + Text('RTL MultiPage', style: const TextStyle(fontSize: 9)), |
355 | + ListView( | ||
356 | + children: [ | ||
291 | for (int i = 0; i < 15; i++) Text('List item'), | 357 | for (int i = 0; i < 15; i++) Text('List item'), |
292 | - ]), | 358 | + ], |
359 | + ), | ||
293 | ]; | 360 | ]; |
294 | }, | 361 | }, |
295 | ), | 362 | ), |
@@ -303,7 +370,7 @@ void main() { | @@ -303,7 +370,7 @@ void main() { | ||
303 | pageFormat: const PdfPageFormat(150, 150), | 370 | pageFormat: const PdfPageFormat(150, 150), |
304 | build: (Context context) { | 371 | build: (Context context) { |
305 | return [ | 372 | return [ |
306 | - Text('LTR MultiPage'), | 373 | + Text('LTR MultiPage', style: const TextStyle(fontSize: 9)), |
307 | ListView(children: [ | 374 | ListView(children: [ |
308 | for (int i = 0; i < 15; i++) Text('List item'), | 375 | for (int i = 0; i < 15; i++) Text('List item'), |
309 | ]), | 376 | ]), |
@@ -444,7 +511,7 @@ void main() { | @@ -444,7 +511,7 @@ void main() { | ||
444 | return TestAnnotation( | 511 | return TestAnnotation( |
445 | anno: 'LTR RadiusDirectional.horizontal end', | 512 | anno: 'LTR RadiusDirectional.horizontal end', |
446 | child: Container( | 513 | child: Container( |
447 | - margin: const EdgeInsets.only(top: 22), | 514 | + margin: const EdgeInsets.only(top: 11), |
448 | decoration: const BoxDecoration( | 515 | decoration: const BoxDecoration( |
449 | color: PdfColors.blue, | 516 | color: PdfColors.blue, |
450 | borderRadius: BorderRadiusDirectional.horizontal( | 517 | borderRadius: BorderRadiusDirectional.horizontal( |
@@ -609,6 +676,7 @@ class TestAnnotation extends StatelessWidget { | @@ -609,6 +676,7 @@ class TestAnnotation extends StatelessWidget { | ||
609 | child: Text( | 676 | child: Text( |
610 | anno, | 677 | anno, |
611 | style: const TextStyle(color: PdfColors.black, fontSize: 9), | 678 | style: const TextStyle(color: PdfColors.black, fontSize: 9), |
679 | + textDirection: TextDirection.ltr, | ||
612 | textAlign: TextAlign.center, | 680 | textAlign: TextAlign.center, |
613 | ), | 681 | ), |
614 | ), | 682 | ), |
-
Please register or login to post a comment