Toggle navigation
Toggle navigation
This project
Loading...
Sign in
flutter_package
/
dart_pdf
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
Milad akarie
2023-07-01 21:09:27 +0300
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Committed by
David PHAM-VAN
2023-07-24 08:39:22 -0300
Commit
dad54ff3b5a3121af676a52becdc645466c0aced
dad54ff3
1 parent
5a00c175
Add RTL support to BorderRadius widget
Add RTL support Alignment
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
638 additions
and
59 deletions
pdf/lib/src/widgets/basic.dart
pdf/lib/src/widgets/border_radius.dart
pdf/lib/src/widgets/decoration.dart
pdf/lib/src/widgets/flex.dart
pdf/lib/src/widgets/forms.dart
pdf/lib/src/widgets/geometry.dart
pdf/lib/src/widgets/wrap.dart
pdf/test/rtl_layout_test.dart
pdf/lib/src/widgets/basic.dart
View file @
dad54ff
...
...
@@ -16,15 +16,10 @@
import
'dart:math'
as
math
;
import
'package:pdf/widgets.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
import
'../../pdf.dart'
;
import
'box_border.dart'
;
import
'container.dart'
;
import
'decoration.dart'
;
import
'geometry.dart'
;
import
'widget.dart'
;
import
'../../widgets.dart'
;
enum
BoxFit
{
fill
,
contain
,
cover
,
fitWidth
,
fitHeight
,
none
,
scaleDown
}
...
...
@@ -303,7 +298,7 @@ class Align extends SingleChildWidget {
super
(
child:
child
);
/// How to align the child.
final
Alignment
alignment
;
final
Alignment
Geometry
alignment
;
/// If non-null, sets its width to the child's width multiplied by this factor.
final
double
?
widthFactor
;
...
...
@@ -330,8 +325,8 @@ class Align extends SingleChildWidget {
height:
shrinkWrapHeight
?
child
!.
box
!.
height
*
(
heightFactor
??
1.0
)
:
double
.
infinity
);
child
!.
box
=
alignment
.
inscribe
(
child
!.
box
!.
size
,
box
!);
final
resolvedAlignment
=
alignment
.
resolve
(
Directionality
.
of
(
context
));
child
!.
box
=
resolvedAlignment
.
inscribe
(
child
!.
box
!.
size
,
box
!);
}
else
{
box
=
constraints
.
constrainRect
(
width:
shrinkWrapWidth
?
0.0
:
double
.
infinity
,
...
...
pdf/lib/src/widgets/border_radius.dart
View file @
dad54ff
...
...
@@ -14,8 +14,10 @@
* limitations under the License.
*/
import
'package:meta/meta.dart'
;
import
'../../pdf.dart'
;
import
'
widget
.dart'
;
import
'
../../widgets
.dart'
;
/// A radius for either circular or elliptical shapes.
class
Radius
{
...
...
@@ -35,8 +37,149 @@ class Radius {
static
const
Radius
zero
=
Radius
.
circular
(
0.0
);
}
/// Base class for [BorderRadius] that allows for text-direction aware resolution.
///
/// A property or argument of this type accepts classes created either with [
/// BorderRadius.only] and its variants, or [BorderRadiusDirectional.only]
/// and its variants.
///
/// To convert a [BorderRadiusGeometry] object of indeterminate type into a
/// [BorderRadius] object, call the [resolve] method.
@immutable
abstract
class
BorderRadiusGeometry
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
BorderRadiusGeometry
();
Radius
get
_topLeft
;
Radius
get
_topRight
;
Radius
get
_bottomLeft
;
Radius
get
_bottomRight
;
Radius
get
_topStart
;
Radius
get
_topEnd
;
Radius
get
_bottomStart
;
Radius
get
_bottomEnd
;
Radius
get
uniform
;
bool
get
isUniform
;
/// Convert this instance into a [BorderRadius], so that the radii are
/// expressed for specific physical corners (top-left, top-right, etc) rather
/// than in a direction-dependent manner.
///
/// See also:
///
/// * [BorderRadius], for which this is a no-op (returns itself).
/// * [BorderRadiusDirectional], which flips the horizontal direction
/// based on the `direction` argument.
BorderRadius
resolve
(
TextDirection
?
direction
);
@override
String
toString
()
{
String
?
visual
,
logical
;
if
(
_topLeft
==
_topRight
&&
_topRight
==
_bottomLeft
&&
_bottomLeft
==
_bottomRight
)
{
if
(
_topLeft
!=
Radius
.
zero
)
{
if
(
_topLeft
.
x
==
_topLeft
.
y
)
{
visual
=
'BorderRadius.circular(
${_topLeft.x.toStringAsFixed(1)}
)'
;
}
else
{
visual
=
'BorderRadius.all(
$_topLeft
)'
;
}
}
}
else
{
// visuals aren't the same and at least one isn't zero
final
result
=
StringBuffer
();
result
.
write
(
'BorderRadius.only('
);
var
comma
=
false
;
if
(
_topLeft
!=
Radius
.
zero
)
{
result
.
write
(
'topLeft:
$_topLeft
'
);
comma
=
true
;
}
if
(
_topRight
!=
Radius
.
zero
)
{
if
(
comma
)
{
result
.
write
(
', '
);
}
result
.
write
(
'topRight:
$_topRight
'
);
comma
=
true
;
}
if
(
_bottomLeft
!=
Radius
.
zero
)
{
if
(
comma
)
{
result
.
write
(
', '
);
}
result
.
write
(
'bottomLeft:
$_bottomLeft
'
);
comma
=
true
;
}
if
(
_bottomRight
!=
Radius
.
zero
)
{
if
(
comma
)
{
result
.
write
(
', '
);
}
result
.
write
(
'bottomRight:
$_bottomRight
'
);
}
result
.
write
(
')'
);
visual
=
result
.
toString
();
}
if
(
_topStart
==
_topEnd
&&
_topEnd
==
_bottomEnd
&&
_bottomEnd
==
_bottomStart
)
{
if
(
_topStart
!=
Radius
.
zero
)
{
if
(
_topStart
.
x
==
_topStart
.
y
)
{
logical
=
'BorderRadiusDirectional.circular(
${_topStart.x.toStringAsFixed(1)}
)'
;
}
else
{
logical
=
'BorderRadiusDirectional.all(
$_topStart
)'
;
}
}
}
else
{
// logical aren't the same and at least one isn't zero
final
result
=
StringBuffer
();
result
.
write
(
'BorderRadiusDirectional.only('
);
var
comma
=
false
;
if
(
_topStart
!=
Radius
.
zero
)
{
result
.
write
(
'topStart:
$_topStart
'
);
comma
=
true
;
}
if
(
_topEnd
!=
Radius
.
zero
)
{
if
(
comma
)
{
result
.
write
(
', '
);
}
result
.
write
(
'topEnd:
$_topEnd
'
);
comma
=
true
;
}
if
(
_bottomStart
!=
Radius
.
zero
)
{
if
(
comma
)
{
result
.
write
(
', '
);
}
result
.
write
(
'bottomStart:
$_bottomStart
'
);
comma
=
true
;
}
if
(
_bottomEnd
!=
Radius
.
zero
)
{
if
(
comma
)
{
result
.
write
(
', '
);
}
result
.
write
(
'bottomEnd:
$_bottomEnd
'
);
}
result
.
write
(
')'
);
logical
=
result
.
toString
();
}
if
(
visual
!=
null
&&
logical
!=
null
)
{
return
'
$visual
+
$logical
'
;
}
if
(
visual
!=
null
)
{
return
visual
;
}
if
(
logical
!=
null
)
{
return
logical
;
}
return
'BorderRadius.zero'
;
}
}
/// An immutable set of radii for each corner of a rectangle.
class
BorderRadius
{
class
BorderRadius
extends
BorderRadiusGeometry
{
/// Creates a border radius where all radii are [radius].
const
BorderRadius
.
all
(
Radius
radius
)
:
this
.
only
(
...
...
@@ -85,6 +228,8 @@ class BorderRadius {
this
.
bottomRight
=
Radius
.
zero
,
});
/// A border radius with all zero radii.
static
const
BorderRadius
zero
=
BorderRadius
.
all
(
Radius
.
zero
);
...
...
@@ -100,6 +245,14 @@ class BorderRadius {
/// The bottom-right [Radius].
final
Radius
bottomRight
;
@override
bool
get
isUniform
=>
topLeft
==
topRight
&&
topLeft
==
bottomLeft
&&
topLeft
==
bottomRight
;
@override
Radius
get
uniform
=>
isUniform
?
topLeft
:
Radius
.
zero
;
void
paint
(
Context
context
,
PdfRect
box
)
{
// Ellipse 4-spline magic number
const
_m4
=
0.551784
;
...
...
@@ -108,23 +261,13 @@ class BorderRadius {
// Start
..
moveTo
(
box
.
x
,
box
.
y
+
bottomLeft
.
y
)
// bottomLeft
..
curveTo
(
box
.
x
,
box
.
y
-
_m4
*
bottomLeft
.
y
+
bottomLeft
.
y
,
box
.
x
-
_m4
*
bottomLeft
.
x
+
bottomLeft
.
x
,
box
.
y
,
box
.
x
+
bottomLeft
.
x
,
box
.
y
)
..
curveTo
(
box
.
x
,
box
.
y
-
_m4
*
bottomLeft
.
y
+
bottomLeft
.
y
,
box
.
x
-
_m4
*
bottomLeft
.
x
+
bottomLeft
.
x
,
box
.
y
,
box
.
x
+
bottomLeft
.
x
,
box
.
y
)
// bottom
..
lineTo
(
box
.
x
+
box
.
width
-
bottomRight
.
x
,
box
.
y
)
// bottomRight
..
curveTo
(
box
.
x
+
_m4
*
bottomRight
.
x
+
box
.
width
-
bottomRight
.
x
,
box
.
y
,
box
.
x
+
box
.
width
,
box
.
y
-
_m4
*
bottomRight
.
y
+
bottomRight
.
y
,
box
.
x
+
box
.
width
,
box
.
y
+
bottomRight
.
y
)
..
curveTo
(
box
.
x
+
_m4
*
bottomRight
.
x
+
box
.
width
-
bottomRight
.
x
,
box
.
y
,
box
.
x
+
box
.
width
,
box
.
y
-
_m4
*
bottomRight
.
y
+
bottomRight
.
y
,
box
.
x
+
box
.
width
,
box
.
y
+
bottomRight
.
y
)
// right
..
lineTo
(
box
.
x
+
box
.
width
,
box
.
y
+
box
.
height
-
topRight
.
y
)
// topRight
...
...
@@ -138,14 +281,165 @@ class BorderRadius {
// top
..
lineTo
(
box
.
x
+
topLeft
.
x
,
box
.
y
+
box
.
height
)
// topLeft
..
curveTo
(
box
.
x
-
_m4
*
topLeft
.
x
+
topLeft
.
x
,
box
.
y
+
box
.
height
,
box
.
x
,
box
.
y
+
_m4
*
topLeft
.
y
+
box
.
height
-
topLeft
.
y
,
box
.
x
,
box
.
y
+
box
.
height
-
topLeft
.
y
)
..
curveTo
(
box
.
x
-
_m4
*
topLeft
.
x
+
topLeft
.
x
,
box
.
y
+
box
.
height
,
box
.
x
,
box
.
y
+
_m4
*
topLeft
.
y
+
box
.
height
-
topLeft
.
y
,
box
.
x
,
box
.
y
+
box
.
height
-
topLeft
.
y
)
// left
..
lineTo
(
box
.
x
,
box
.
y
+
bottomLeft
.
y
);
}
@override
Radius
get
_topLeft
=>
topLeft
;
@override
Radius
get
_topRight
=>
topRight
;
@override
Radius
get
_bottomLeft
=>
bottomLeft
;
@override
Radius
get
_bottomRight
=>
bottomRight
;
@override
Radius
get
_topStart
=>
Radius
.
zero
;
@override
Radius
get
_topEnd
=>
Radius
.
zero
;
@override
Radius
get
_bottomStart
=>
Radius
.
zero
;
@override
Radius
get
_bottomEnd
=>
Radius
.
zero
;
@override
BorderRadius
resolve
(
TextDirection
?
direction
)
=>
this
;
}
/// An immutable set of radii for each corner of a rectangle, but with the
/// corners specified in a manner dependent on the writing direction.
///
/// This can be used to specify a corner radius on the leading or trailing edge
/// of a box, so that it flips to the other side when the text alignment flips
/// (e.g. being on the top right in English text but the top left in Arabic
/// text).
///
/// See also:
///
/// * [BorderRadius], a variant that uses physical labels (`topLeft` and
/// `topRight` instead of `topStart` and `topEnd`).
class
BorderRadiusDirectional
extends
BorderRadiusGeometry
{
/// Creates a border radius where all radii are [radius].
const
BorderRadiusDirectional
.
all
(
Radius
radius
)
:
this
.
only
(
topStart:
radius
,
topEnd:
radius
,
bottomStart:
radius
,
bottomEnd:
radius
,
);
/// Creates a border radius where all radii are [Radius.circular(radius)].
BorderRadiusDirectional
.
circular
(
double
radius
)
:
this
.
all
(
Radius
.
circular
(
radius
),
);
/// Creates a vertically symmetric border radius where the top and bottom
/// sides of the rectangle have the same radii.
const
BorderRadiusDirectional
.
vertical
({
Radius
top
=
Radius
.
zero
,
Radius
bottom
=
Radius
.
zero
,
})
:
this
.
only
(
topStart:
top
,
topEnd:
top
,
bottomStart:
bottom
,
bottomEnd:
bottom
,
);
/// Creates a horizontally symmetrical border radius where the start and end
/// sides of the rectangle have the same radii.
const
BorderRadiusDirectional
.
horizontal
({
Radius
start
=
Radius
.
zero
,
Radius
end
=
Radius
.
zero
,
})
:
this
.
only
(
topStart:
start
,
topEnd:
end
,
bottomStart:
start
,
bottomEnd:
end
,
);
/// Creates a border radius with only the given non-zero values. The other
/// corners will be right angles.
const
BorderRadiusDirectional
.
only
({
this
.
topStart
=
Radius
.
zero
,
this
.
topEnd
=
Radius
.
zero
,
this
.
bottomStart
=
Radius
.
zero
,
this
.
bottomEnd
=
Radius
.
zero
,
});
/// A border radius with all zero radii.
///
/// Consider using [BorderRadius.zero] instead, since that object has the same
/// effect, but will be cheaper to [resolve].
static
const
BorderRadiusDirectional
zero
=
BorderRadiusDirectional
.
all
(
Radius
.
zero
);
/// The top-start [Radius].
final
Radius
topStart
;
@override
Radius
get
_topStart
=>
topStart
;
/// The top-end [Radius].
final
Radius
topEnd
;
@override
Radius
get
_topEnd
=>
topEnd
;
/// The bottom-start [Radius].
final
Radius
bottomStart
;
@override
Radius
get
_bottomStart
=>
bottomStart
;
/// The bottom-end [Radius].
final
Radius
bottomEnd
;
@override
Radius
get
_bottomEnd
=>
bottomEnd
;
@override
Radius
get
_topLeft
=>
Radius
.
zero
;
@override
Radius
get
_topRight
=>
Radius
.
zero
;
@override
Radius
get
_bottomLeft
=>
Radius
.
zero
;
@override
Radius
get
_bottomRight
=>
Radius
.
zero
;
@override
bool
get
isUniform
=>
topStart
==
topEnd
&&
topStart
==
bottomStart
&&
topStart
==
bottomEnd
;
@override
Radius
get
uniform
=>
isUniform
?
topStart
:
Radius
.
zero
;
@override
BorderRadius
resolve
(
TextDirection
?
direction
)
{
assert
(
direction
!=
null
);
switch
(
direction
!)
{
case
TextDirection
.
rtl
:
return
BorderRadius
.
only
(
topLeft:
topEnd
,
topRight:
topStart
,
bottomLeft:
bottomEnd
,
bottomRight:
bottomStart
,
);
case
TextDirection
.
ltr
:
return
BorderRadius
.
only
(
topLeft:
topStart
,
topRight:
topEnd
,
bottomLeft:
bottomStart
,
bottomRight:
bottomEnd
,
);
}
}
}
\ No newline at end of file
...
...
pdf/lib/src/widgets/decoration.dart
View file @
dad54ff
...
...
@@ -20,12 +20,7 @@ import 'package:meta/meta.dart';
import
'package:vector_math/vector_math_64.dart'
;
import
'../../pdf.dart'
;
import
'basic.dart'
;
import
'border_radius.dart'
;
import
'box_border.dart'
;
import
'geometry.dart'
;
import
'image_provider.dart'
;
import
'widget.dart'
;
import
'../../widgets.dart'
;
enum
DecorationPosition
{
background
,
foreground
}
...
...
@@ -271,7 +266,7 @@ class BoxDecoration {
/// The color to fill in the background of the box.
final
PdfColor
?
color
;
final
BoxBorder
?
border
;
final
BorderRadius
?
borderRadius
;
final
BorderRadius
Geometry
?
borderRadius
;
final
BoxShape
shape
;
final
DecorationGraphic
?
image
;
final
Gradient
?
gradient
;
...
...
@@ -282,11 +277,12 @@ class BoxDecoration {
PdfRect
box
,
[
PaintPhase
phase
=
PaintPhase
.
all
,
])
{
final
resolvedBorderRadius
=
borderRadius
?.
resolve
(
Directionality
.
of
(
context
));
if
(
phase
==
PaintPhase
.
all
||
phase
==
PaintPhase
.
background
)
{
if
(
color
!=
null
)
{
switch
(
shape
)
{
case
BoxShape
.
rectangle
:
if
(
b
orderRadius
==
null
)
{
if
(
resolvedB
orderRadius
==
null
)
{
if
(
boxShadow
!=
null
)
{
for
(
final
s
in
boxShadow
!)
{
final
i
=
PdfRasterBase
.
shadowRect
(
box
.
width
,
box
.
height
,
...
...
@@ -313,7 +309,7 @@ class BoxDecoration {
);
}
}
borderRadius
!
.
paint
(
context
,
box
);
resolvedBorderRadius
.
paint
(
context
,
box
);
}
break
;
case
BoxShape
.
circle
:
...
...
@@ -341,10 +337,10 @@ class BoxDecoration {
if
(
gradient
!=
null
)
{
switch
(
shape
)
{
case
BoxShape
.
rectangle
:
if
(
b
orderRadius
==
null
)
{
if
(
resolvedB
orderRadius
==
null
)
{
context
.
canvas
.
drawBox
(
box
);
}
else
{
borderRadius
!
.
paint
(
context
,
box
);
resolvedBorderRadius
.
paint
(
context
,
box
);
}
break
;
case
BoxShape
.
circle
:
...
...
@@ -367,8 +363,8 @@ class BoxDecoration {
break
;
case
BoxShape
.
rectangle
:
if
(
borderRadius
!=
null
)
{
borderRadius
!.
paint
(
context
,
box
);
if
(
resolvedBorderRadius
!=
null
)
{
resolvedBorderRadius
.
paint
(
context
,
box
);
context
.
canvas
.
clipPath
();
}
break
;
...
...
@@ -384,7 +380,7 @@ class BoxDecoration {
context
,
box
,
shape:
shape
,
borderRadius:
b
orderRadius
,
borderRadius:
resolvedB
orderRadius
,
);
}
}
...
...
pdf/lib/src/widgets/flex.dart
View file @
dad54ff
...
...
@@ -16,14 +16,10 @@
import
'dart:math'
as
math
;
import
'package:pdf/widgets.dart'
;
import
'package:vector_math/vector_math_64.dart'
;
import
'../../pdf.dart'
;
import
'basic.dart'
;
import
'geometry.dart'
;
import
'multi_page.dart'
;
import
'widget.dart'
;
import
'../../widgets.dart'
;
enum
FlexFit
{
tight
,
...
...
pdf/lib/src/widgets/forms.dart
View file @
dad54ff
...
...
@@ -146,7 +146,7 @@ class Checkbox extends SingleChildWidget with AnnotationAppearance {
BoxDecoration
?
decoration
,
})
:
radius
=
decoration
?.
shape
==
BoxShape
.
circle
?
Radius
.
circular
(
math
.
max
(
height
,
width
)
/
2
)
:
decoration
?.
borderRadius
?.
topLeft
??
Radius
.
zero
,
:
decoration
?.
borderRadius
?.
uniform
??
Radius
.
zero
,
super
(
child:
Container
(
width:
width
,
...
...
pdf/lib/src/widgets/geometry.dart
View file @
dad54ff
...
...
@@ -566,7 +566,35 @@ class EdgeInsetsDirectional extends EdgeInsetsGeometry {
}
}
class
Alignment
{
/// Base class for [Alignment] that allows for text-direction aware
/// resolution.
///
/// A property or argument of this type accepts classes created either with [
/// Alignment] and its variants, or [AlignmentDirectional.new].
///
/// To convert an [AlignmentGeometry] object of indeterminate type into an
/// [Alignment] object, call the [resolve] method.
@immutable
abstract
class
AlignmentGeometry
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
AlignmentGeometry
();
/// Convert this instance into an [Alignment], which uses literal
/// coordinates (the `x` coordinate being explicitly a distance from the
/// left).
///
/// See also:
///
/// * [Alignment], for which this is a no-op (returns itself).
/// * [AlignmentDirectional], which flips the horizontal direction
/// based on the `direction` argument.
Alignment
resolve
(
TextDirection
?
direction
);
}
class
Alignment
extends
AlignmentGeometry
{
const
Alignment
(
this
.
x
,
this
.
y
);
/// The distance fraction in the horizontal direction.
...
...
@@ -633,9 +661,169 @@ class Alignment {
}
@override
String
toString
()
=>
'(
$x
,
$y
)'
;
String
toString
()
=>
_stringify
(
x
,
y
);
static
String
_stringify
(
double
x
,
double
y
)
{
if
(
x
==
-
1.0
&&
y
==
-
1.0
)
{
return
'Alignment.topLeft'
;
}
if
(
x
==
0.0
&&
y
==
-
1.0
)
{
return
'Alignment.topCenter'
;
}
if
(
x
==
1.0
&&
y
==
-
1.0
)
{
return
'Alignment.topRight'
;
}
if
(
x
==
-
1.0
&&
y
==
0.0
)
{
return
'Alignment.centerLeft'
;
}
if
(
x
==
0.0
&&
y
==
0.0
)
{
return
'Alignment.center'
;
}
if
(
x
==
1.0
&&
y
==
0.0
)
{
return
'Alignment.centerRight'
;
}
if
(
x
==
-
1.0
&&
y
==
1.0
)
{
return
'Alignment.bottomLeft'
;
}
if
(
x
==
0.0
&&
y
==
1.0
)
{
return
'Alignment.bottomCenter'
;
}
if
(
x
==
1.0
&&
y
==
1.0
)
{
return
'Alignment.bottomRight'
;
}
return
'Alignment(
${x.toStringAsFixed(1)}
, '
'
${y.toStringAsFixed(1)}
)'
;
}
@override
Alignment
resolve
(
TextDirection
?
direction
)
=>
this
;
}
/// An offset that's expressed as a fraction of a [Size], but whose horizontal
/// component is dependent on the writing direction.
///
/// This can be used to indicate an offset from the left in [TextDirection.ltr]
/// text and an offset from the right in [TextDirection.rtl] text without having
/// to be aware of the current text direction.
///
/// See also:
///
/// * [Alignment], a variant that is defined in physical terms (i.e.
/// whose horizontal component does not depend on the text direction).
class
AlignmentDirectional
extends
AlignmentGeometry
{
/// Creates a directional alignment.
///
/// The [start] and [y] arguments must not be null.
const
AlignmentDirectional
(
this
.
start
,
this
.
y
);
/// The distance fraction in the horizontal direction.
///
/// A value of -1.0 corresponds to the edge on the "start" side, which is the
/// left side in [TextDirection.ltr] contexts and the right side in
/// [TextDirection.rtl] contexts. A value of 1.0 corresponds to the opposite
/// edge, the "end" side. Values are not limited to that range; values less
/// than -1.0 represent positions beyond the start edge, and values greater than
/// 1.0 represent positions beyond the end edge.
///
/// This value is normalized into an [Alignment.x] value by the [resolve]
/// method.
final
double
start
;
/// The distance fraction in the vertical direction.
///
/// A value of -1.0 corresponds to the topmost edge. A value of 1.0
/// corresponds to the bottommost edge. Values are not limited to that range;
/// values less than -1.0 represent positions above the top, and values
/// greater than 1.0 represent positions below the bottom.
///
/// This value is passed through to [Alignment.y] unmodified by the
/// [resolve] method.
final
double
y
;
/// The top corner on the "start" side.
static
const
AlignmentDirectional
topStart
=
AlignmentDirectional
(-
1.0
,
-
1.0
);
/// The center point along the top edge.
///
/// Consider using [Alignment.topCenter] instead, as it does not need
/// to be [resolve]d to be used.
static
const
AlignmentDirectional
topCenter
=
AlignmentDirectional
(
0.0
,
-
1.0
);
/// The top corner on the "end" side.
static
const
AlignmentDirectional
topEnd
=
AlignmentDirectional
(
1.0
,
-
1.0
);
/// The center point along the "start" edge.
static
const
AlignmentDirectional
centerStart
=
AlignmentDirectional
(-
1.0
,
0.0
);
/// The center point, both horizontally and vertically.
///
/// Consider using [Alignment.center] instead, as it does not need to
/// be [resolve]d to be used.
static
const
AlignmentDirectional
center
=
AlignmentDirectional
(
0.0
,
0.0
);
/// The center point along the "end" edge.
static
const
AlignmentDirectional
centerEnd
=
AlignmentDirectional
(
1.0
,
0.0
);
/// The bottom corner on the "start" side.
static
const
AlignmentDirectional
bottomStart
=
AlignmentDirectional
(-
1.0
,
1.0
);
/// The center point along the bottom edge.
///
/// Consider using [Alignment.bottomCenter] instead, as it does not
/// need to be [resolve]d to be used.
static
const
AlignmentDirectional
bottomCenter
=
AlignmentDirectional
(
0.0
,
1.0
);
/// The bottom corner on the "end" side.
static
const
AlignmentDirectional
bottomEnd
=
AlignmentDirectional
(
1.0
,
1.0
);
static
String
_stringify
(
double
start
,
double
y
)
{
if
(
start
==
-
1.0
&&
y
==
-
1.0
)
{
return
'AlignmentDirectional.topStart'
;
}
if
(
start
==
0.0
&&
y
==
-
1.0
)
{
return
'AlignmentDirectional.topCenter'
;
}
if
(
start
==
1.0
&&
y
==
-
1.0
)
{
return
'AlignmentDirectional.topEnd'
;
}
if
(
start
==
-
1.0
&&
y
==
0.0
)
{
return
'AlignmentDirectional.centerStart'
;
}
if
(
start
==
0.0
&&
y
==
0.0
)
{
return
'AlignmentDirectional.center'
;
}
if
(
start
==
1.0
&&
y
==
0.0
)
{
return
'AlignmentDirectional.centerEnd'
;
}
if
(
start
==
-
1.0
&&
y
==
1.0
)
{
return
'AlignmentDirectional.bottomStart'
;
}
if
(
start
==
0.0
&&
y
==
1.0
)
{
return
'AlignmentDirectional.bottomCenter'
;
}
if
(
start
==
1.0
&&
y
==
1.0
)
{
return
'AlignmentDirectional.bottomEnd'
;
}
return
'AlignmentDirectional(
${start.toStringAsFixed(1)}
, '
'
${y.toStringAsFixed(1)}
)'
;
}
@override
String
toString
()
=>
_stringify
(
start
,
y
);
@override
Alignment
resolve
(
TextDirection
?
direction
)
{
assert
(
direction
!=
null
,
'Cannot resolve
$runtimeType
without a TextDirection.'
);
switch
(
direction
!)
{
case
TextDirection
.
rtl
:
return
Alignment
(-
start
,
y
);
case
TextDirection
.
ltr
:
return
Alignment
(
start
,
y
);
}
}
}
/// An offset that's expressed as a fraction of a [PdfPoint].
@immutable
class
FractionalOffset
extends
Alignment
{
...
...
pdf/lib/src/widgets/wrap.dart
View file @
dad54ff
...
...
@@ -16,14 +16,10 @@
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
'widget.dart'
;
import
'../../widgets.dart'
;
/// How [Wrap] should align objects.
enum
WrapAlignment
{
...
...
pdf/test/rtl_layout_test.dart
View file @
dad54ff
...
...
@@ -284,6 +284,120 @@ void main() {
);
});
test
(
'Should render a blue box aligned center right'
,
()
{
pdf
.
addPage
(
Page
(
textDirection:
TextDirection
.
rtl
,
pageFormat:
const
PdfPageFormat
(
150
,
150
),
build:
(
Context
context
)
{
return
Align
(
alignment:
AlignmentDirectional
.
centerStart
,
child:
_blueBox
,
);
},
),
);
});
test
(
'Should render a blue box aligned center left'
,
()
{
pdf
.
addPage
(
Page
(
textDirection:
TextDirection
.
ltr
,
pageFormat:
const
PdfPageFormat
(
150
,
150
),
build:
(
Context
context
)
{
return
Align
(
alignment:
AlignmentDirectional
.
centerStart
,
child:
_blueBox
,
);
},
),
);
});
test
(
'Should render a box with top-right curved corner'
,
()
{
pdf
.
addPage
(
Page
(
textDirection:
TextDirection
.
rtl
,
pageFormat:
const
PdfPageFormat
(
150
,
150
),
build:
(
Context
context
)
{
return
Container
(
decoration:
const
BoxDecoration
(
color:
PdfColors
.
blue
,
borderRadius:
BorderRadiusDirectional
.
only
(
topStart:
Radius
.
circular
(
20
),
),
),
width:
150
,
height:
150
,
);
},
),
);
});
test
(
'Should render a box with right curved corners'
,
()
{
pdf
.
addPage
(
Page
(
textDirection:
TextDirection
.
rtl
,
pageFormat:
const
PdfPageFormat
(
150
,
150
),
build:
(
Context
context
)
{
return
Container
(
decoration:
const
BoxDecoration
(
color:
PdfColors
.
blue
,
borderRadius:
BorderRadiusDirectional
.
horizontal
(
start:
Radius
.
circular
(
20
),
),
),
width:
150
,
height:
150
,
);
},
),
);
});
test
(
'Should render a box with left curved corners'
,
()
{
pdf
.
addPage
(
Page
(
textDirection:
TextDirection
.
ltr
,
pageFormat:
const
PdfPageFormat
(
150
,
150
),
build:
(
Context
context
)
{
return
Container
(
decoration:
const
BoxDecoration
(
color:
PdfColors
.
blue
,
borderRadius:
BorderRadiusDirectional
.
horizontal
(
start:
Radius
.
circular
(
20
),
),
),
width:
150
,
height:
150
,
);
},
),
);
});
test
(
'Should render a box with top-left curved corner'
,
()
{
pdf
.
addPage
(
Page
(
textDirection:
TextDirection
.
ltr
,
pageFormat:
const
PdfPageFormat
(
150
,
150
),
build:
(
Context
context
)
{
return
Container
(
decoration:
const
BoxDecoration
(
color:
PdfColors
.
blue
,
borderRadius:
BorderRadiusDirectional
.
only
(
topStart:
Radius
.
circular
(
20
),
),
),
width:
150
,
height:
150
,
);
},
),
);
});
tearDownAll
(()
async
{
final
file
=
File
(
'rtl-layout.pdf'
);
await
file
.
writeAsBytes
(
await
pdf
.
save
());
...
...
Please
register
or
login
to post a comment