Milad akarie
Committed by David PHAM-VAN

Add RTL support to Flex widget

@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 16
17 import 'dart:math' as math; 17 import 'dart:math' as math;
18 18
  19 +import 'package:pdf/widgets.dart';
19 import 'package:vector_math/vector_math_64.dart'; 20 import 'package:vector_math/vector_math_64.dart';
20 21
21 import '../../pdf.dart'; 22 import '../../pdf.dart';
@@ -396,10 +397,10 @@ class Flex extends MultiChildWidget with SpanningWidget { @@ -396,10 +397,10 @@ class Flex extends MultiChildWidget with SpanningWidget {
396 final remainingSpace = math.max(0.0, actualSizeDelta); 397 final remainingSpace = math.max(0.0, actualSizeDelta);
397 double? leadingSpace; 398 double? leadingSpace;
398 late double betweenSpace; 399 late double betweenSpace;
399 - final flipMainAxis = (verticalDirection == VerticalDirection.down &&  
400 - direction == Axis.vertical) ||  
401 - (verticalDirection == VerticalDirection.up &&  
402 - direction == Axis.horizontal); 400 +
  401 + final textDirection = Directionality.of(context) ;
  402 + final flipMainAxis = !(_startIsTopLeft(direction, textDirection, verticalDirection) ?? true);
  403 +
403 switch (mainAxisAlignment) { 404 switch (mainAxisAlignment) {
404 case MainAxisAlignment.start: 405 case MainAxisAlignment.start:
405 leadingSpace = 0.0; 406 leadingSpace = 0.0;
@@ -430,10 +431,6 @@ class Flex extends MultiChildWidget with SpanningWidget { @@ -430,10 +431,6 @@ class Flex extends MultiChildWidget with SpanningWidget {
430 } 431 }
431 432
432 // Position elements 433 // Position elements
433 - final flipCrossAxis = (verticalDirection == VerticalDirection.down &&  
434 - direction == Axis.horizontal) ||  
435 - (verticalDirection == VerticalDirection.up &&  
436 - direction == Axis.vertical);  
437 var childMainPosition = 434 var childMainPosition =
438 flipMainAxis ? actualSize - leadingSpace : leadingSpace; 435 flipMainAxis ? actualSize - leadingSpace : leadingSpace;
439 436
@@ -442,12 +439,11 @@ class Flex extends MultiChildWidget with SpanningWidget { @@ -442,12 +439,11 @@ class Flex extends MultiChildWidget with SpanningWidget {
442 double? childCrossPosition; 439 double? childCrossPosition;
443 switch (crossAxisAlignment) { 440 switch (crossAxisAlignment) {
444 case CrossAxisAlignment.start: 441 case CrossAxisAlignment.start:
445 - childCrossPosition =  
446 - flipCrossAxis ? crossSize - _getCrossSize(child) : 0.0;  
447 - break;  
448 case CrossAxisAlignment.end: 442 case CrossAxisAlignment.end:
449 - childCrossPosition =  
450 - !flipCrossAxis ? crossSize - _getCrossSize(child) : 0.0; 443 + childCrossPosition = _startIsTopLeft(flipAxis(direction), textDirection, verticalDirection)
  444 + == (crossAxisAlignment == CrossAxisAlignment.start)
  445 + ? 0.0
  446 + : crossSize - _getCrossSize(child);
451 break; 447 break;
452 case CrossAxisAlignment.center: 448 case CrossAxisAlignment.center:
453 childCrossPosition = crossSize / 2.0 - _getCrossSize(child) / 2.0; 449 childCrossPosition = crossSize / 2.0 - _getCrossSize(child) / 2.0;
@@ -478,6 +474,39 @@ class Flex extends MultiChildWidget with SpanningWidget { @@ -478,6 +474,39 @@ class Flex extends MultiChildWidget with SpanningWidget {
478 } 474 }
479 } 475 }
480 476
  477 + Axis flipAxis(Axis direction) {
  478 + switch (direction) {
  479 + case Axis.horizontal:
  480 + return Axis.vertical;
  481 + case Axis.vertical:
  482 + return Axis.horizontal;
  483 + }
  484 + }
  485 +
  486 + bool? _startIsTopLeft(Axis direction, TextDirection? textDirection, VerticalDirection? verticalDirection) {
  487 + // If the relevant value of textDirection or verticalDirection is null, this returns null too.
  488 + switch (direction) {
  489 + case Axis.horizontal:
  490 + switch (textDirection) {
  491 + case TextDirection.ltr:
  492 + return true;
  493 + case TextDirection.rtl:
  494 + return false;
  495 + case null:
  496 + return null;
  497 + }
  498 + case Axis.vertical:
  499 + switch (verticalDirection) {
  500 + case VerticalDirection.down:
  501 + return false;
  502 + case VerticalDirection.up:
  503 + return true;
  504 + case null:
  505 + return null;
  506 + }
  507 + }
  508 + }
  509 +
481 @override 510 @override
482 void paint(Context context) { 511 void paint(Context context) {
483 super.paint(context); 512 super.paint(context);
  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 +
  19 +import 'package:pdf/pdf.dart';
  20 +import 'package:pdf/widgets.dart';
  21 +import 'package:test/test.dart';
  22 +
  23 +late Document pdf;
  24 +
  25 +final _blueBox = Container(
  26 + width: 50,
  27 + height: 50,
  28 + color: PdfColors.blue,
  29 +);
  30 +
  31 +final _redBox = Container(
  32 + width: 50,
  33 + height: 50,
  34 + color: PdfColors.red,
  35 +);
  36 +
  37 +void main() {
  38 + setUpAll(() {
  39 + Document.debug = true;
  40 + pdf = Document();
  41 + });
  42 +
  43 + test('Should render a blue box followed by a red box ordered RTL aligned right', () {
  44 + pdf.addPage(
  45 + Page(
  46 + textDirection: TextDirection.rtl,
  47 + pageFormat: const PdfPageFormat(150, 50),
  48 + build: (Context context) => Row(
  49 + children: [_blueBox, _redBox],
  50 + ),
  51 + ),
  52 + );
  53 + });
  54 +
  55 + test('Should render a blue box followed by a red box ordered RTL with aligned center', () {
  56 + pdf.addPage(
  57 + Page(
  58 + textDirection: TextDirection.rtl,
  59 + pageFormat: const PdfPageFormat(150, 50),
  60 + build: (Context context) => Row(
  61 + mainAxisAlignment: MainAxisAlignment.center,
  62 + children: [_blueBox, _redBox],
  63 + ),
  64 + ),
  65 + );
  66 + });
  67 +
  68 + test('Should render a blue box followed by a red box ordered RTL with CrossAxisAlignment.end aligned right', () {
  69 + pdf.addPage(
  70 + Page(
  71 + pageFormat: const PdfPageFormat(150, 100),
  72 + textDirection: TextDirection.rtl,
  73 + build: (Context context) => SizedBox(
  74 + width: 150,
  75 + height: 100,
  76 + child: Row(
  77 + crossAxisAlignment: CrossAxisAlignment.end,
  78 + children: [_blueBox, _redBox],
  79 + ),
  80 + ),
  81 + ),
  82 + );
  83 + });
  84 + test('Should render a blue box followed by a red box ordered LTR aligned left', () {
  85 + pdf.addPage(
  86 + Page(
  87 + pageFormat: const PdfPageFormat(150, 50),
  88 + build: (Context context) => Row(
  89 + children: [_blueBox, _redBox],
  90 + ),
  91 + ),
  92 + );
  93 + });
  94 + test('Should render a blue box followed by a red box ordered TTB aligned right', () {
  95 + pdf.addPage(
  96 + Page(
  97 + textDirection: TextDirection.rtl,
  98 + pageFormat: const PdfPageFormat(150, 150),
  99 + build: (Context context) => SizedBox(
  100 + width: 150,
  101 + height: 150,
  102 + child: Column(
  103 + crossAxisAlignment: CrossAxisAlignment.start,
  104 + children: [_blueBox, _redBox],
  105 + ),
  106 + ),
  107 + ),
  108 + );
  109 + });
  110 + test('Should render a blue box followed by a red box ordered TTB aligned left', () {
  111 + pdf.addPage(
  112 + Page(
  113 + textDirection: TextDirection.ltr,
  114 + pageFormat: const PdfPageFormat(150, 150),
  115 + build: (Context context) => SizedBox(
  116 + width: 150,
  117 + height: 150,
  118 + child: Column(
  119 + crossAxisAlignment: CrossAxisAlignment.start,
  120 + children: [_blueBox, _redBox],
  121 + ),
  122 + ),
  123 + ),
  124 + );
  125 + });
  126 +
  127 + tearDownAll(() async {
  128 + final file = File('rtl-layout.pdf');
  129 + await file.writeAsBytes(await pdf.save());
  130 + });
  131 +}