Milad akarie
Committed by David PHAM-VAN

Add RTL support to GridView

... ... @@ -38,13 +38,13 @@ class ChartLegend extends StatelessWidget {
final TextStyle? textStyle;
final Alignment position;
final AlignmentGeometry position;
final Axis direction;
final BoxDecoration? decoration;
final EdgeInsets padding;
final EdgeInsetsGeometry padding;
Widget _buildLegend(Context context, Dataset dataset) {
final style = Theme.of(context).defaultTextStyle.merge(textStyle);
... ...
... ... @@ -75,9 +75,9 @@ class Container extends StatelessWidget {
final Widget? child;
final Alignment? alignment;
final AlignmentGeometry? alignment;
final EdgeInsets? padding;
final EdgeInsetsGeometry? padding;
/// The decoration to paint behind the [child].
final BoxDecoration? decoration;
... ... @@ -89,7 +89,7 @@ class Container extends StatelessWidget {
final BoxConstraints? constraints;
/// Empty space to surround the [decoration] and [child].
final EdgeInsets? margin;
final EdgeInsetsGeometry? margin;
/// The transformation matrix to apply before painting the container.
final Matrix4? transform;
... ...
... ... @@ -56,9 +56,9 @@ class Header extends StatelessWidget {
final BoxDecoration? decoration;
final EdgeInsets? margin;
final EdgeInsetsGeometry? margin;
final EdgeInsets? padding;
final EdgeInsetsGeometry? padding;
final TextStyle? textStyle;
... ... @@ -190,9 +190,9 @@ class Paragraph extends StatelessWidget {
final TextStyle? style;
final EdgeInsets margin;
final EdgeInsetsGeometry margin;
final EdgeInsets? padding;
final EdgeInsetsGeometry? padding;
@override
Widget build(Context context) {
... ... @@ -232,11 +232,11 @@ class Bullet extends StatelessWidget {
final TextStyle? style;
final EdgeInsets margin;
final EdgeInsetsGeometry margin;
final EdgeInsets? padding;
final EdgeInsetsGeometry? padding;
final EdgeInsets bulletMargin;
final EdgeInsetsGeometry bulletMargin;
final double bulletSize;
... ...
... ... @@ -649,7 +649,7 @@ class ListView extends StatelessWidget {
super();
final Axis direction;
final EdgeInsets? padding;
final EdgeInsetsGeometry? padding;
final double? spacing;
final bool reverse;
final IndexedWidgetBuilder? itemBuilder;
... ...
... ... @@ -15,9 +15,7 @@
*/
import '../../pdf.dart';
import 'box_border.dart';
import 'geometry.dart';
import 'widget.dart';
import '../../widgets.dart';
/// A widget that draws a rectilinear grid of lines.
/// The grid is drawn over the [child] widget.
... ... @@ -187,7 +185,7 @@ class GridPaper extends SingleChildWidget {
final int verticalSubdivisions;
/// The margin to apply to the horizontal and vertical lines
final EdgeInsets margin;
final EdgeInsetsGeometry margin;
final int horizontalOffset;
... ... @@ -202,12 +200,14 @@ class GridPaper extends SingleChildWidget {
@override
void layout(Context context, BoxConstraints constraints,
{bool parentUsesSize = false}) {
final resolvedMargin = margin.resolve(Directionality.of(context));
box = PdfRect.fromPoints(PdfPoint.zero, constraints.biggest);
if (child != null) {
if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) {
final childConstraints = BoxConstraints(
maxWidth: constraints.maxWidth - margin.horizontal,
maxHeight: constraints.maxHeight - margin.vertical,
maxWidth: constraints.maxWidth - resolvedMargin.horizontal,
maxHeight: constraints.maxHeight - resolvedMargin.vertical,
);
child!.layout(context, childConstraints, parentUsesSize: false);
} else {
... ... @@ -216,7 +216,7 @@ class GridPaper extends SingleChildWidget {
assert(child!.box != null);
child!.box = PdfRect.fromPoints(
PdfPoint(margin.left, box!.top - margin.top - child!.box!.height),
PdfPoint(resolvedMargin.left, box!.top - resolvedMargin.top - child!.box!.height),
child!.box!.size);
}
}
... ... @@ -225,7 +225,7 @@ class GridPaper extends SingleChildWidget {
void paint(Context context) {
super.paint(context);
paintChild(context);
final resolvedMargin = margin.resolve(Directionality.of(context));
context.canvas.saveContext();
context.canvas.setGraphicState(PdfGraphicState(opacity: opacity));
context.canvas.setStrokeColor(horizontalColor);
... ... @@ -236,8 +236,8 @@ class GridPaper extends SingleChildWidget {
final allHorizontalDivisions =
(horizontalDivisions * horizontalSubdivisions).toDouble();
var n = horizontalOffset;
for (var x = box!.left + margin.left;
x <= box!.right - margin.right;
for (var x = box!.left + resolvedMargin.left;
x <= box!.right - resolvedMargin.right;
x += horizontalInterval / allHorizontalDivisions) {
context.canvas
..setLineWidth((n % (horizontalSubdivisions * horizontalDivisions) == 0)
... ... @@ -254,8 +254,8 @@ class GridPaper extends SingleChildWidget {
final allVerticalDivisions =
(verticalDivisions * verticalSubdivisions).toDouble();
n = verticalOffset;
for (var y = box!.top - margin.top;
y >= box!.bottom + margin.bottom;
for (var y = box!.top - resolvedMargin.top;
y >= box!.bottom + resolvedMargin.bottom;
y -= verticalInterval / allVerticalDivisions) {
context.canvas
..setLineWidth((n % (verticalSubdivisions * verticalDivisions) == 0)
... ... @@ -273,7 +273,7 @@ class GridPaper extends SingleChildWidget {
context.canvas
..setStrokeColor(border.left.color)
..setLineWidth(border.left.width)
..drawLine(box!.left + margin.left, box!.top, box!.left + margin.left,
..drawLine(box!.left + resolvedMargin.left, box!.top, box!.left + resolvedMargin.left,
box!.bottom)
..strokePath();
border.left.style.unsetStyle(context);
... ... @@ -283,8 +283,8 @@ class GridPaper extends SingleChildWidget {
context.canvas
..setStrokeColor(border.right.color)
..setLineWidth(border.right.width)
..drawLine(box!.right - margin.right, box!.top,
box!.right - margin.right, box!.bottom)
..drawLine(box!.right - resolvedMargin.right, box!.top,
box!.right - resolvedMargin.right, box!.bottom)
..strokePath();
border.right.style.unsetStyle(context);
}
... ... @@ -294,7 +294,7 @@ class GridPaper extends SingleChildWidget {
..setStrokeColor(border.top.color)
..setLineWidth(border.top.width)
..drawLine(
box!.left, box!.top - margin.top, box!.right, box!.top - margin.top)
box!.left, box!.top - resolvedMargin.top, box!.right, box!.top - resolvedMargin.top)
..strokePath();
border.top.style.unsetStyle(context);
}
... ... @@ -303,8 +303,8 @@ class GridPaper extends SingleChildWidget {
context.canvas
..setStrokeColor(border.bottom.color)
..setLineWidth(border.bottom.width)
..drawLine(box!.left, box!.bottom + margin.bottom, box!.right,
box!.bottom + margin.bottom)
..drawLine(box!.left, box!.bottom + resolvedMargin.bottom, box!.right,
box!.bottom + resolvedMargin.bottom)
..strokePath();
border.bottom.style.unsetStyle(context);
}
... ...
... ... @@ -16,12 +16,14 @@
import 'dart:math' as math;
import 'package:pdf/widgets.dart';
import 'package:vector_math/vector_math_64.dart';
import '../../pdf.dart';
import 'flex.dart';
import 'geometry.dart';
import 'multi_page.dart';
import 'text_style.dart';
import 'widget.dart';
class GridViewContext extends WidgetContext {
... ... @@ -45,8 +47,7 @@ class GridViewContext extends WidgetContext {
}
@override
String toString() =>
'$runtimeType first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis';
String toString() => '$runtimeType first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis';
}
class GridView extends MultiChildWidget with SpanningWidget {
... ... @@ -61,7 +62,7 @@ class GridView extends MultiChildWidget with SpanningWidget {
: super(children: children);
final Axis direction;
final EdgeInsets padding;
final EdgeInsetsGeometry padding;
final int crossAxisCount;
final double mainAxisSpacing;
final double crossAxisSpacing;
... ... @@ -72,8 +73,7 @@ class GridView extends MultiChildWidget with SpanningWidget {
int? _mainAxisCount;
@override
void layout(Context context, BoxConstraints constraints,
{bool parentUsesSize = false}) {
void layout(Context context, BoxConstraints constraints, {bool parentUsesSize = false}) {
if (children.isEmpty) {
box = PdfRect.zero;
return;
... ... @@ -81,13 +81,13 @@ class GridView extends MultiChildWidget with SpanningWidget {
assert(() {
if (constraints.maxHeight.isInfinite && childAspectRatio.isInfinite) {
print(
'Unable to calculate the GridView dimensions. Please set the height constraints or childAspectRatio.');
print('Unable to calculate the GridView dimensions. Please set the height constraints or childAspectRatio.');
return false;
}
return true;
}());
final textDirection = Directionality.of(context);
final resolvedPadding = padding.resolve(textDirection);
late double mainAxisExtent;
late double crossAxisExtent;
switch (direction) {
... ... @@ -102,25 +102,19 @@ class GridView extends MultiChildWidget with SpanningWidget {
}
if (constraints.maxHeight.isInfinite || _mainAxisCount == null) {
_mainAxisCount =
((children.length - _context.firstChild) / crossAxisCount).ceil();
_mainAxisCount = ((children.length - _context.firstChild) / crossAxisCount).ceil();
_context.childCrossAxis = crossAxisExtent / crossAxisCount -
(crossAxisSpacing * (crossAxisCount - 1) / crossAxisCount);
_context.childCrossAxis =
crossAxisExtent / crossAxisCount - (crossAxisSpacing * (crossAxisCount - 1) / crossAxisCount);
_context.childMainAxis = math.min(
_context.childCrossAxis! * childAspectRatio,
mainAxisExtent / _mainAxisCount! -
(mainAxisSpacing * (_mainAxisCount! - 1) / _mainAxisCount!));
_context.childMainAxis = math.min(_context.childCrossAxis! * childAspectRatio,
mainAxisExtent / _mainAxisCount! - (mainAxisSpacing * (_mainAxisCount! - 1) / _mainAxisCount!));
if (_context.childCrossAxis!.isInfinite) {
throw Exception(
'Unable to calculate child height as the height constraint is infinite.');
throw Exception('Unable to calculate child height as the height constraint is infinite.');
}
} else {
_mainAxisCount = ((mainAxisExtent + mainAxisSpacing) /
(mainAxisSpacing + _context.childMainAxis!))
.floor();
_mainAxisCount = ((mainAxisExtent + mainAxisSpacing) / (mainAxisSpacing + _context.childMainAxis!)).floor();
if (_mainAxisCount! < 0) {
// Not enough space to put one line, try to ask for more space.
... ... @@ -128,28 +122,22 @@ class GridView extends MultiChildWidget with SpanningWidget {
}
}
final totalMain =
(_context.childMainAxis! + mainAxisSpacing) * _mainAxisCount! -
mainAxisSpacing;
final totalCross =
(_context.childCrossAxis! + crossAxisSpacing) * crossAxisCount -
crossAxisSpacing;
final totalMain = (_context.childMainAxis! + mainAxisSpacing) * _mainAxisCount! - mainAxisSpacing;
final totalCross = (_context.childCrossAxis! + crossAxisSpacing) * crossAxisCount - crossAxisSpacing;
final startX = padding.left;
final startX = resolvedPadding.left;
const startY = 0.0;
late double mainAxis;
late double crossAxis;
BoxConstraints? innerConstraints;
switch (direction) {
case Axis.vertical:
innerConstraints = BoxConstraints.tightFor(
width: _context.childCrossAxis, height: _context.childMainAxis);
innerConstraints = BoxConstraints.tightFor(width: _context.childCrossAxis, height: _context.childMainAxis);
crossAxis = startX;
mainAxis = startY;
break;
case Axis.horizontal:
innerConstraints = BoxConstraints.tightFor(
width: _context.childMainAxis, height: _context.childCrossAxis);
innerConstraints = BoxConstraints.tightFor(width: _context.childMainAxis, height: _context.childCrossAxis);
mainAxis = startX;
crossAxis = startY;
break;
... ... @@ -158,10 +146,9 @@ class GridView extends MultiChildWidget with SpanningWidget {
var c = 0;
_context.lastChild = _context.firstChild;
final isRtl = textDirection == TextDirection.rtl;
for (final child in children.sublist(
_context.firstChild,
math.min(children.length,
_context.firstChild + crossAxisCount * _mainAxisCount!))) {
_context.firstChild, math.min(children.length, _context.firstChild + crossAxisCount * _mainAxisCount!))) {
child.layout(context, innerConstraints);
assert(child.box != null);
... ... @@ -169,21 +156,26 @@ class GridView extends MultiChildWidget with SpanningWidget {
case Axis.vertical:
child.box = PdfRect.fromPoints(
PdfPoint(
(_context.childCrossAxis! - child.box!.width) / 2.0 +
crossAxis,
isRtl
? (_context.childCrossAxis! + child.box!.width - crossAxis)
: (_context.childCrossAxis! - child.box!.width) / 2.0 + crossAxis,
totalMain +
padding.bottom -
resolvedPadding.bottom -
(_context.childMainAxis! - child.box!.height) / 2.0 -
mainAxis -
child.box!.height),
child.box!.height,
),
child.box!.size);
break;
case Axis.horizontal:
child.box = PdfRect.fromPoints(
PdfPoint(
(_context.childMainAxis! - child.box!.width) / 2.0 + mainAxis,
isRtl
? totalMain - (child.box!.width + mainAxis)
: (_context.childMainAxis! - child.box!.width) / 2.0 + mainAxis,
totalCross +
padding.bottom -
resolvedPadding.bottom -
(_context.childCrossAxis! - child.box!.height) / 2.0 -
crossAxis -
child.box!.height),
... ... @@ -216,14 +208,10 @@ class GridView extends MultiChildWidget with SpanningWidget {
switch (direction) {
case Axis.vertical:
box = constraints.constrainRect(
width: totalCross + padding.horizontal,
height: totalMain + padding.vertical);
box = constraints.constrainRect(width: totalCross + padding.horizontal, height: totalMain + padding.vertical);
break;
case Axis.horizontal:
box = constraints.constrainRect(
width: totalMain + padding.horizontal,
height: totalCross + padding.vertical);
box = constraints.constrainRect(width: totalMain + padding.horizontal, height: totalCross + padding.vertical);
break;
}
}
... ... @@ -235,6 +223,7 @@ class GridView extends MultiChildWidget with SpanningWidget {
if (children.isEmpty) {
return;
}
final resolvedPadding = padding.resolve(Directionality.of(context));
context.canvas
..setFillColor(PdfColors.lime)
... ... @@ -242,35 +231,26 @@ class GridView extends MultiChildWidget with SpanningWidget {
..lineTo(box!.right, box!.bottom)
..lineTo(box!.right, box!.top)
..lineTo(box!.left, box!.top)
..moveTo(box!.left + padding.left, box!.bottom + padding.bottom)
..lineTo(box!.left + padding.left, box!.top - padding.top)
..lineTo(box!.right - padding.right, box!.top - padding.top)
..lineTo(box!.right - padding.right, box!.bottom + padding.bottom)
..moveTo(box!.left + resolvedPadding.left, box!.bottom + resolvedPadding.bottom)
..lineTo(box!.left + resolvedPadding.left, box!.top - resolvedPadding.top)
..lineTo(box!.right - resolvedPadding.right, box!.top - resolvedPadding.top)
..lineTo(box!.right - resolvedPadding.right, box!.bottom + resolvedPadding.bottom)
..fillPath();
for (var c = 1; c < crossAxisCount; c++) {
switch (direction) {
case Axis.vertical:
context.canvas
..drawRect(
box!.left +
padding.left +
(_context.childCrossAxis! + crossAxisSpacing) * c -
crossAxisSpacing,
box!.bottom + padding.bottom,
math.max(crossAxisSpacing, 1),
box!.height - padding.vertical)
..drawRect(box!.left + resolvedPadding.left + (_context.childCrossAxis! + crossAxisSpacing) * c - crossAxisSpacing,
box!.bottom + resolvedPadding.bottom, math.max(crossAxisSpacing, 1), box!.height - resolvedPadding.vertical)
..fillPath();
break;
case Axis.horizontal:
context.canvas
..drawRect(
box!.left + padding.left,
box!.bottom +
padding.bottom +
(_context.childCrossAxis! + crossAxisSpacing) * c -
crossAxisSpacing,
box!.width - padding.horizontal,
box!.left + resolvedPadding.left,
box!.bottom + resolvedPadding.bottom + (_context.childCrossAxis! + crossAxisSpacing) * c - crossAxisSpacing,
box!.width - resolvedPadding.horizontal,
math.max(crossAxisSpacing, 1))
..fillPath();
break;
... ... @@ -282,25 +262,16 @@ class GridView extends MultiChildWidget with SpanningWidget {
case Axis.vertical:
context.canvas
..drawRect(
box!.left + padding.left,
box!.bottom +
padding.bottom +
(_context.childMainAxis! + mainAxisSpacing) * c -
mainAxisSpacing,
box!.width - padding.horizontal,
box!.left + resolvedPadding.left,
box!.bottom + resolvedPadding.bottom + (_context.childMainAxis! + mainAxisSpacing) * c - mainAxisSpacing,
box!.width - resolvedPadding.horizontal,
math.max(mainAxisSpacing, 1))
..fillPath();
break;
case Axis.horizontal:
context.canvas
..drawRect(
box!.left +
padding.left +
(_context.childMainAxis! + mainAxisSpacing) * c -
mainAxisSpacing,
box!.bottom + padding.bottom,
math.max(mainAxisSpacing, 1),
box!.height - padding.vertical)
..drawRect(box!.left + resolvedPadding.left + (_context.childMainAxis! + mainAxisSpacing) * c - mainAxisSpacing,
box!.bottom + resolvedPadding.bottom, math.max(mainAxisSpacing, 1), box!.height - resolvedPadding.vertical)
..fillPath();
break;
}
... ... @@ -317,8 +288,7 @@ class GridView extends MultiChildWidget with SpanningWidget {
..saveContext()
..setTransform(mat);
for (var child
in children.sublist(_context.firstChild, _context.lastChild)) {
for (var child in children.sublist(_context.firstChild, _context.lastChild)) {
child.paint(context);
}
context.canvas.restoreContext();
... ...
... ... @@ -38,7 +38,7 @@ mixin TableHelper {
static Table fromTextArray({
Context? context,
required List<List<dynamic>> data,
EdgeInsets cellPadding = const EdgeInsets.all(5),
EdgeInsetsGeometry cellPadding = const EdgeInsets.all(5),
double cellHeight = 0,
Alignment cellAlignment = Alignment.topLeft,
Map<int, Alignment>? cellAlignments,
... ... @@ -48,7 +48,7 @@ mixin TableHelper {
OnCellDecoration? cellDecoration,
int headerCount = 1,
List<dynamic>? headers,
EdgeInsets? headerPadding,
EdgeInsetsGeometry? headerPadding,
double? headerHeight,
Alignment headerAlignment = Alignment.center,
Map<int, Alignment>? headerAlignments,
... ...
... ... @@ -40,7 +40,6 @@ final _yellowBox = Container(
color: PdfColors.yellow,
);
void main() {
setUpAll(() {
Document.debug = true;
... ... @@ -227,10 +226,7 @@ void main() {
pageFormat: const PdfPageFormat(150, 150),
build: (Context context) {
return [
ListView(children: [
for(int i = 0; i < 30; i++)
Text('Hello World')
]),
ListView(children: [for (int i = 0; i < 30; i++) Text('Hello World')]),
];
},
),
... ... @@ -244,10 +240,7 @@ void main() {
pageFormat: const PdfPageFormat(150, 150),
build: (Context context) {
return [
ListView(children: [
for(int i = 0; i < 30; i++)
Text('Hello World')
]),
ListView(children: [for (int i = 0; i < 30; i++) Text('Hello World')]),
];
},
),
... ... @@ -398,6 +391,93 @@ void main() {
);
});
test('Should render Grid with run alignment right', () {
pdf.addPage(
Page(
textDirection: TextDirection.rtl,
pageFormat: const PdfPageFormat(150, 150),
build: (Context context) {
return GridView(
crossAxisCount: 3,
childAspectRatio: 1,
direction: Axis.vertical,
children: [
for (int i = 0; i < 8; i++)
Container(
color: [PdfColors.blue, PdfColors.red, PdfColors.yellow][i % 3],
),
],
);
},
),
);
});
test('Should render Grid with run alignment left', () {
pdf.addPage(
Page(
textDirection: TextDirection.ltr,
pageFormat: const PdfPageFormat(150, 150),
build: (Context context) {
return GridView(
crossAxisCount: 3,
childAspectRatio: 1,
direction: Axis.vertical,
children: [
for (int i = 0; i < 7; i++)
Container(
color: [PdfColors.blue, PdfColors.red, PdfColors.yellow][i % 3],
),
],
);
},
),
);
});
test('Should render Grid (horizontal) with run alignment right', () {
pdf.addPage(
Page(
textDirection: TextDirection.rtl,
pageFormat: const PdfPageFormat(150, 150),
build: (Context context) {
return GridView(
crossAxisCount: 3,
childAspectRatio: 1,
direction: Axis.horizontal,
children: [
for (int i = 0; i < 7; i++)
Container(
color: [PdfColors.blue, PdfColors.red, PdfColors.yellow][i % 3],
),
],
);
},
),
);
});
test('Should render Grid (horizontal) with run alignment left', () {
pdf.addPage(
Page(
textDirection: TextDirection.ltr,
pageFormat: const PdfPageFormat(150, 150),
build: (Context context) {
return GridView(
crossAxisCount: 3,
childAspectRatio: 1,
direction: Axis.horizontal,
children: [
for (int i = 0; i < 7; i++)
Container(
color: [PdfColors.blue, PdfColors.red, PdfColors.yellow][i % 3],
),
],
);
},
),
);
});
tearDownAll(() async {
final file = File('rtl-layout.pdf');
await file.writeAsBytes(await pdf.save());
... ...