David PHAM-VAN

Improve Border and BorderSide objects

... ... @@ -122,12 +122,13 @@ class Calendar extends StatelessWidget {
return Expanded(
child: Container(
foregroundDecoration: BoxDecoration(
border: BoxBorder(
color: PdfColors.grey,
top: true,
left: true,
right: index % 7 == 6,
bottom: true,
border: Border(
top: const BorderSide(color: PdfColors.grey),
left: const BorderSide(color: PdfColors.grey),
right: index % 7 == 6
? const BorderSide(color: PdfColors.grey)
: BorderSide.none,
bottom: const BorderSide(color: PdfColors.grey),
),
),
child: header(context, d),
... ... @@ -146,13 +147,13 @@ class Calendar extends StatelessWidget {
d.day == _date.day;
return Container(
foregroundDecoration: BoxDecoration(
border: BoxBorder(
color: PdfColors.grey,
left: true,
right: index % 7 == 6,
bottom: true,
),
),
border: Border(
left: const BorderSide(color: PdfColors.grey),
right: index % 7 == 6
? const BorderSide(color: PdfColors.grey)
: BorderSide.none,
bottom: const BorderSide(color: PdfColors.grey),
)),
child: day(context, d, currentMonth, currentDay),
);
}),
... ...
... ... @@ -35,8 +35,8 @@ Future<Uint8List> generateDocument(PdfPageFormat format) async {
margin: const pw.EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
padding: const pw.EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
decoration: const pw.BoxDecoration(
border: pw.BoxBorder(
bottom: true, width: 0.5, color: PdfColors.grey)),
border: pw.Border(
bottom: pw.BorderSide(width: 0.5, color: PdfColors.grey))),
child: pw.Text('Portable Document Format',
style: pw.Theme.of(context)
.defaultTextStyle
... ...
... ... @@ -449,10 +449,7 @@ class Invoice {
children: [
pw.Container(
decoration: pw.BoxDecoration(
border: pw.BoxBorder(
top: true,
color: accentColor,
),
border: pw.Border(top: pw.BorderSide(color: accentColor)),
),
padding: const pw.EdgeInsets.only(top: 10, bottom: 4),
child: pw.Text(
... ... @@ -518,12 +515,13 @@ class Invoice {
fontSize: 10,
),
rowDecoration: pw.BoxDecoration(
border: pw.BoxBorder(
bottom: true,
border: pw.Border(
bottom: pw.BorderSide(
color: accentColor,
width: .5,
),
),
),
headers: List<String>.generate(
tableHeaders.length,
(col) => tableHeaders[col],
... ...
... ... @@ -150,12 +150,13 @@ Future<Uint8List> generateReport(PdfPageFormat pageFormat) async {
color: baseColor,
),
rowDecoration: pw.BoxDecoration(
border: pw.BoxBorder(
bottom: true,
border: pw.Border(
bottom: pw.BorderSide(
color: baseColor,
width: .5,
),
),
),
);
return pw.Column(
... ...
... ... @@ -237,7 +237,7 @@ class _Block extends pw.StatelessWidget {
]),
pw.Container(
decoration: const pw.BoxDecoration(
border: pw.BoxBorder(left: true, color: green, width: 2)),
border: pw.Border(left: pw.BorderSide(color: green, width: 2))),
padding: const pw.EdgeInsets.only(left: 10, top: 5, bottom: 5),
margin: const pw.EdgeInsets.only(left: 5),
child: pw.Column(
... ...
... ... @@ -220,6 +220,24 @@ class PdfColor {
@override
String toString() => '$runtimeType($red, $green, $blue, $alpha)';
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is PdfColor &&
other.red == red &&
other.green == green &&
other.blue == blue &&
other.alpha == alpha;
}
@override
int get hashCode => toInt();
}
/// Represents an CMYK color
... ...
... ... @@ -19,6 +19,8 @@ export 'package:barcode/barcode.dart';
export 'widgets/annotations.dart';
export 'widgets/barcode.dart';
export 'widgets/basic.dart';
export 'widgets/border_radius.dart';
export 'widgets/box_border.dart';
export 'widgets/chart/bar_chart.dart';
export 'widgets/chart/chart.dart';
export 'widgets/chart/grid_axis.dart';
... ...
... ... @@ -20,6 +20,7 @@ import 'package:meta/meta.dart';
import 'package:pdf/pdf.dart';
import 'package:vector_math/vector_math_64.dart';
import 'box_border.dart';
import 'container.dart';
import 'decoration.dart';
import 'geometry.dart';
... ... @@ -815,14 +816,15 @@ class Divider extends StatelessWidget {
height: thickness,
margin: EdgeInsets.only(left: indent, right: endIndent),
decoration: BoxDecoration(
border: BoxBorder(
bottom: true,
border: Border(
bottom: BorderSide(
color: color,
width: thickness,
),
),
),
),
),
);
}
}
... ... @@ -869,14 +871,15 @@ class VerticalDivider extends StatelessWidget {
width: thickness,
margin: EdgeInsets.only(top: indent, bottom: endIndent),
decoration: BoxDecoration(
border: BoxBorder(
left: true,
border: Border(
left: BorderSide(
color: color,
width: thickness,
),
),
),
),
),
);
}
}
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:pdf/pdf.dart';
import 'widget.dart';
/// A radius for either circular or elliptical shapes.
class Radius {
/// Constructs a circular radius. [x] and [y] will have the same radius value.
const Radius.circular(double radius) : this.elliptical(radius, radius);
/// Constructs an elliptical radius with the given radii.
const Radius.elliptical(this.x, this.y);
/// The radius value on the horizontal axis.
final double x;
/// The radius value on the vertical axis.
final double y;
/// A radius with [x] and [y] values set to zero.
static const Radius zero = Radius.circular(0.0);
}
/// An immutable set of radii for each corner of a rectangle.
class BorderRadius {
/// Creates a border radius where all radii are [radius].
const BorderRadius.all(Radius radius)
: this.only(
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
);
/// Creates a border radius where all radii are [Radius.circular(radius)].
BorderRadius.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 BorderRadius.vertical({
Radius top = Radius.zero,
Radius bottom = Radius.zero,
}) : this.only(
topLeft: top,
topRight: top,
bottomLeft: bottom,
bottomRight: bottom,
);
/// Creates a horizontally symmetrical border radius where the left and right
/// sides of the rectangle have the same radii.
const BorderRadius.horizontal({
Radius left = Radius.zero,
Radius right = Radius.zero,
}) : this.only(
topLeft: left,
topRight: right,
bottomLeft: left,
bottomRight: right,
);
/// Creates a border radius with only the given non-zero values. The other
/// corners will be right angles.
const BorderRadius.only({
this.topLeft = Radius.zero,
this.topRight = Radius.zero,
this.bottomLeft = Radius.zero,
this.bottomRight = Radius.zero,
});
/// A border radius with all zero radii.
static const BorderRadius zero = BorderRadius.all(Radius.zero);
/// The top-left [Radius].
final Radius topLeft;
/// The top-right [Radius].
final Radius topRight;
/// The bottom-left [Radius].
final Radius bottomLeft;
/// The bottom-right [Radius].
final Radius bottomRight;
void paint(Context context, PdfRect box) {
// Ellipse 4-spline magic number
const _m4 = 0.551784;
context.canvas
// 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)
// 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)
// right
..lineTo(box.x + box.width, box.y + box.height - topRight.y)
// topRight
..curveTo(
box.x + box.width,
box.y + _m4 * topRight.y + box.height - topRight.y,
box.x + _m4 * topRight.x + box.width - topRight.x,
box.y + box.height,
box.x + box.width - topRight.x,
box.y + box.height)
// 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)
// left
..lineTo(box.x, box.y + bottomLeft.y);
}
}
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'package:meta/meta.dart';
import 'package:pdf/pdf.dart';
import 'border_radius.dart';
import 'decoration.dart';
import 'widget.dart';
enum BorderStyle { none, solid, dashed, dotted }
@immutable
abstract class BoxBorder {
@Deprecated('Use Border instead')
factory BoxBorder({
bool left = false,
bool top = false,
bool right = false,
bool bottom = false,
PdfColor color = PdfColors.black,
double width = 1.0,
BorderStyle style = BorderStyle.solid,
}) {
assert(color != null);
assert(width != null);
assert(width >= 0.0);
assert(style != null);
return Border(
top: BorderSide(
color: color, width: width, style: top ? style : BorderStyle.none),
bottom: BorderSide(
color: color,
width: width,
style: bottom ? style : BorderStyle.none),
left: BorderSide(
color: color, width: width, style: left ? style : BorderStyle.none),
right: BorderSide(
color: color,
width: width,
style: right ? style : BorderStyle.none));
}
const BoxBorder.P();
BorderSide get top;
BorderSide get bottom;
BorderSide get left;
BorderSide get right;
bool get isUniform;
void paint(
Context context,
PdfRect box, {
BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadius,
});
static void _setStyle(Context context, BorderStyle style) {
switch (style) {
case BorderStyle.none:
case BorderStyle.solid:
break;
case BorderStyle.dashed:
context.canvas
..saveContext()
..setLineDashPattern(const <int>[3, 3]);
break;
case BorderStyle.dotted:
context.canvas
..saveContext()
..setLineDashPattern(const <int>[1, 1]);
break;
}
}
static void _unsetStyle(Context context, BorderStyle style) {
switch (style) {
case BorderStyle.none:
case BorderStyle.solid:
break;
case BorderStyle.dashed:
case BorderStyle.dotted:
context.canvas.restoreContext();
break;
}
}
static void _paintUniformBorderWithCircle(
Context context, PdfRect box, BorderSide side) {
_setStyle(context, side.style);
context.canvas
..setStrokeColor(side.color)
..setLineWidth(side.width)
..drawEllipse(box.x + box.width / 2.0, box.y + box.height / 2.0,
box.width / 2.0, box.height / 2.0)
..strokePath();
_unsetStyle(context, side.style);
}
static void _paintUniformBorderWithRadius(Context context, PdfRect box,
BorderSide side, BorderRadius borderRadius) {
_setStyle(context, side.style);
context.canvas
..setStrokeColor(side.color)
..setLineWidth(side.width);
borderRadius.paint(context, box);
context.canvas.strokePath();
_unsetStyle(context, side.style);
}
static void _paintUniformBorderWithRectangle(
Context context, PdfRect box, BorderSide side) {
_setStyle(context, side.style);
context.canvas
..setStrokeColor(side.color)
..setLineWidth(side.width)
..drawBox(box)
..strokePath();
_unsetStyle(context, side.style);
}
}
/// A side of a border of a box.
class BorderSide {
/// Creates the side of a border.
const BorderSide({
this.color = PdfColors.black,
this.width = 1.0,
this.style = BorderStyle.solid,
});
/// A hairline black border that is not rendered.
static const BorderSide none =
BorderSide(width: 0.0, style: BorderStyle.none);
/// The color of this side of the border.
final PdfColor color;
/// The width of this side of the border.
final double width;
/// The style of this side of the border.
final BorderStyle style;
BorderSide copyWith({
PdfColor color,
double width,
BorderStyle style,
}) =>
BorderSide(
color: color,
width: width,
style: style,
);
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is BorderSide &&
other.color == color &&
other.width == width &&
other.style == style;
}
@override
int get hashCode => color.hashCode + width.hashCode + style.hashCode;
}
/// A border of a box, comprised of four sides: top, right, bottom, left.
class Border extends BoxBorder {
const Border({
this.top = BorderSide.none,
this.right = BorderSide.none,
this.bottom = BorderSide.none,
this.left = BorderSide.none,
}) : assert(top != null),
assert(right != null),
assert(bottom != null),
assert(left != null),
super.P();
/// A uniform border with all sides the same color and width.
factory Border.all({
PdfColor color = PdfColors.black,
double width = 1.0,
BorderStyle style = BorderStyle.solid,
}) =>
Border.fromBorderSide(
BorderSide(color: color, width: width, style: style),
);
/// Creates a border whose sides are all the same.
const Border.fromBorderSide(BorderSide side)
: assert(side != null),
top = side,
right = side,
bottom = side,
left = side,
super.P();
/// Creates a border with symmetrical vertical and horizontal sides.
const Border.symmetric({
BorderSide vertical = BorderSide.none,
BorderSide horizontal = BorderSide.none,
}) : assert(vertical != null),
assert(horizontal != null),
left = vertical,
top = horizontal,
right = vertical,
bottom = horizontal,
super.P();
@override
final BorderSide top;
@override
final BorderSide bottom;
@override
final BorderSide left;
@override
final BorderSide right;
@override
bool get isUniform => top == bottom && bottom == left && left == right;
@override
void paint(
Context context,
PdfRect box, {
BoxShape shape = BoxShape.rectangle,
BorderRadius borderRadius,
}) {
assert(box.x != null);
assert(box.y != null);
assert(box.width != null);
assert(box.height != null);
if (isUniform) {
if (top.style == BorderStyle.none) {
return;
}
switch (shape) {
case BoxShape.circle:
assert(borderRadius == null,
'A borderRadius can only be given for rectangular boxes.');
BoxBorder._paintUniformBorderWithCircle(context, box, top);
break;
case BoxShape.rectangle:
if (borderRadius != null) {
BoxBorder._paintUniformBorderWithRadius(
context, box, top, borderRadius);
return;
}
BoxBorder._paintUniformBorderWithRectangle(context, box, top);
break;
}
return;
}
context.canvas..setLineCap(PdfLineCap.square);
if (top.style != BorderStyle.none) {
BoxBorder._setStyle(context, top.style);
context.canvas
..setStrokeColor(top.color)
..setLineWidth(top.width)
..drawLine(box.left, box.top, box.right, box.top)
..strokePath();
BoxBorder._unsetStyle(context, top.style);
}
if (right.style != BorderStyle.none) {
BoxBorder._setStyle(context, right.style);
context.canvas
..setStrokeColor(right.color)
..setLineWidth(right.width)
..drawLine(box.right, box.top, box.right, box.bottom)
..strokePath();
BoxBorder._unsetStyle(context, right.style);
}
if (bottom.style != BorderStyle.none) {
BoxBorder._setStyle(context, bottom.style);
context.canvas
..setStrokeColor(bottom.color)
..setLineWidth(bottom.width)
..drawLine(box.right, box.bottom, box.left, box.bottom)
..strokePath();
BoxBorder._unsetStyle(context, bottom.style);
}
if (left.style != BorderStyle.none) {
BoxBorder._setStyle(context, left.style);
context.canvas
..setStrokeColor(left.color)
..setLineWidth(left.width)
..drawLine(box.left, box.top, box.left, box.bottom)
..strokePath();
BoxBorder._unsetStyle(context, left.style);
}
}
}
... ...
... ... @@ -18,6 +18,7 @@ import 'package:meta/meta.dart';
import 'package:pdf/pdf.dart';
import 'package:vector_math/vector_math_64.dart';
import '../box_border.dart';
import '../container.dart';
import '../decoration.dart';
import '../flex.dart';
... ...
... ... @@ -21,6 +21,7 @@ import 'package:pdf/pdf.dart';
import 'annotations.dart';
import 'basic.dart';
import 'box_border.dart';
import 'container.dart';
import 'decoration.dart';
import 'flex.dart';
... ... @@ -78,14 +79,14 @@ class Header extends StatelessWidget {
_margin ??= const EdgeInsets.only(bottom: 5.0 * PdfPageFormat.mm);
_padding ??= const EdgeInsets.only(bottom: 1.0 * PdfPageFormat.mm);
_decoration ??=
const BoxDecoration(border: BoxBorder(bottom: true, width: 1));
const BoxDecoration(border: Border(bottom: BorderSide()));
_textStyle ??= Theme.of(context).header0;
break;
case 1:
_margin ??= const EdgeInsets.only(
top: 3.0 * PdfPageFormat.mm, bottom: 5.0 * PdfPageFormat.mm);
_decoration ??=
const BoxDecoration(border: BoxBorder(bottom: true, width: 0.2));
const BoxDecoration(border: Border(bottom: BorderSide(width: 0.2)));
_textStyle ??= Theme.of(context).header1;
break;
case 2:
... ...
... ... @@ -22,204 +22,14 @@ import 'package:pdf/pdf.dart';
import 'package:vector_math/vector_math_64.dart';
import 'basic.dart';
import 'border_radius.dart';
import 'box_border.dart';
import 'geometry.dart';
import 'image_provider.dart';
import 'widget.dart';
enum DecorationPosition { background, foreground }
enum BorderStyle { none, solid, dashed, dotted }
@immutable
class BoxBorder {
const BoxBorder({
this.left = false,
this.top = false,
this.right = false,
this.bottom = false,
this.color = PdfColors.black,
this.width = 1.0,
this.style = BorderStyle.solid,
}) : assert(color != null),
assert(width != null),
assert(width >= 0.0),
assert(style != null);
final bool top;
final bool bottom;
final bool left;
final bool right;
final BorderStyle style;
/// The color of the
final PdfColor color;
/// The width of the
final double width;
void paintRect(Context context, PdfRect box) {
assert(box.x != null);
assert(box.y != null);
assert(box.width != null);
assert(box.height != null);
if (!(top || bottom || left || right)) {
return;
}
switch (style) {
case BorderStyle.none:
return;
case BorderStyle.solid:
break;
case BorderStyle.dashed:
context.canvas
..saveContext()
..setLineDashPattern(const <int>[3, 3]);
break;
case BorderStyle.dotted:
context.canvas
..saveContext()
..setLineDashPattern(const <int>[1, 1]);
break;
}
context.canvas
..setStrokeColor(color)
..setLineWidth(width);
if (top) {
context.canvas.drawLine(box.x, box.top, box.right, box.top);
}
if (right) {
if (!top) {
context.canvas.moveTo(box.right, box.top);
}
context.canvas.lineTo(box.right, box.y);
}
if (bottom) {
if (!right) {
context.canvas.moveTo(box.right, box.y);
}
context.canvas.lineTo(box.x, box.y);
}
if (left) {
if (!bottom) {
context.canvas.moveTo(box.x, box.y);
context.canvas.lineTo(box.x, box.top);
} else if (right && top) {
context.canvas.strokePath(close: true);
} else {
context.canvas.lineTo(box.x, box.top);
}
}
context.canvas.strokePath();
if (style != BorderStyle.solid) {
context.canvas.restoreContext();
}
}
void paintEllipse(Context context, PdfRect box) {
assert(box.x != null);
assert(box.y != null);
assert(box.width != null);
assert(box.height != null);
context.canvas
..setStrokeColor(color)
..setLineWidth(width)
..drawEllipse(box.x + box.width / 2.0, box.y + box.height / 2.0,
box.width / 2.0, box.height / 2.0)
..strokePath();
}
void paintRRect(Context context, PdfRect box, BorderRadius borderRadius) {
assert(box.x != null);
assert(box.y != null);
assert(box.width != null);
assert(box.height != null);
context.canvas
..setStrokeColor(color)
..setLineWidth(width);
borderRadius.paint(context, box);
context.canvas.strokePath();
}
}
/// A side of a border of a box.
class BorderSide {
/// Creates the side of a border.
const BorderSide({
this.color = PdfColors.black,
this.width = 1.0,
this.style = BorderStyle.solid,
});
/// The color of this side of the border.
final PdfColor color;
/// The width of this side of the border.
final double width;
/// The style of this side of the border.
final BorderStyle style;
BorderSide copyWith({
PdfColor color,
double width,
BorderStyle style,
}) =>
BorderSide(
color: color,
width: width,
style: style,
);
}
/// A border of a box, comprised of four sides: top, right, bottom, left.
class Border extends BoxBorder {
const Border._(bool left, bool top, bool right, bool bottom, PdfColor color,
double width, BorderStyle style)
: super(
left: left,
top: top,
right: right,
bottom: bottom,
color: color,
width: width,
style: style,
);
/// A uniform border with all sides the same color and width.
factory Border.all({
PdfColor color = PdfColors.black,
double width = 1.0,
BorderStyle style = BorderStyle.solid,
}) =>
Border._(
true,
true,
true,
true,
color,
width,
style,
);
/// Creates a border whose sides are all the same.
factory Border.fromBorderSide(BorderSide side) => Border.all(
color: side.color,
width: side.width,
style: side.style,
);
}
@immutable
class DecorationImage {
@Deprecated('Use DecorationImage.provider()')
... ... @@ -498,139 +308,6 @@ enum BoxShape { circle, rectangle }
enum PaintPhase { all, background, foreground }
/// A radius for either circular or elliptical shapes.
class Radius {
/// Constructs a circular radius. [x] and [y] will have the same radius value.
const Radius.circular(double radius) : this.elliptical(radius, radius);
/// Constructs an elliptical radius with the given radii.
const Radius.elliptical(this.x, this.y);
/// The radius value on the horizontal axis.
final double x;
/// The radius value on the vertical axis.
final double y;
/// A radius with [x] and [y] values set to zero.
static const Radius zero = Radius.circular(0.0);
}
/// An immutable set of radii for each corner of a rectangle.
class BorderRadius {
/// Creates a border radius where all radii are [radius].
const BorderRadius.all(Radius radius)
: this.only(
topLeft: radius,
topRight: radius,
bottomLeft: radius,
bottomRight: radius,
);
/// Creates a border radius where all radii are [Radius.circular(radius)].
BorderRadius.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 BorderRadius.vertical({
Radius top = Radius.zero,
Radius bottom = Radius.zero,
}) : this.only(
topLeft: top,
topRight: top,
bottomLeft: bottom,
bottomRight: bottom,
);
/// Creates a horizontally symmetrical border radius where the left and right
/// sides of the rectangle have the same radii.
const BorderRadius.horizontal({
Radius left = Radius.zero,
Radius right = Radius.zero,
}) : this.only(
topLeft: left,
topRight: right,
bottomLeft: left,
bottomRight: right,
);
/// Creates a border radius with only the given non-zero values. The other
/// corners will be right angles.
const BorderRadius.only({
this.topLeft = Radius.zero,
this.topRight = Radius.zero,
this.bottomLeft = Radius.zero,
this.bottomRight = Radius.zero,
});
/// A border radius with all zero radii.
static const BorderRadius zero = BorderRadius.all(Radius.zero);
/// The top-left [Radius].
final Radius topLeft;
/// The top-right [Radius].
final Radius topRight;
/// The bottom-left [Radius].
final Radius bottomLeft;
/// The bottom-right [Radius].
final Radius bottomRight;
void paint(Context context, PdfRect box) {
// Ellipse 4-spline magic number
const _m4 = 0.551784;
context.canvas
// 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)
// 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)
// right
..lineTo(box.x + box.width, box.y + box.height - topRight.y)
// topRight
..curveTo(
box.x + box.width,
box.y + _m4 * topRight.y + box.height - topRight.y,
box.x + _m4 * topRight.x + box.width - topRight.x,
box.y + box.height,
box.x + box.width - topRight.x,
box.y + box.height)
// 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)
// left
..lineTo(box.x, box.y + bottomLeft.y);
}
}
@immutable
class BoxDecoration {
const BoxDecoration({
... ... @@ -768,18 +445,12 @@ class BoxDecoration {
if (phase == PaintPhase.all || phase == PaintPhase.foreground) {
if (border != null) {
switch (shape) {
case BoxShape.circle:
border.paintEllipse(context, box);
break;
case BoxShape.rectangle:
if (borderRadius != null) {
border.paintRRect(context, box, borderRadius);
} else {
border.paintRect(context, box);
}
break;
}
border.paint(
context,
box,
shape: shape,
borderRadius: borderRadius,
);
}
}
}
... ...
... ... @@ -18,6 +18,8 @@ import 'package:meta/meta.dart';
import 'package:pdf/pdf.dart';
import 'package:vector_math/vector_math_64.dart';
import 'border_radius.dart';
import 'box_border.dart';
import 'container.dart';
import 'decoration.dart';
import 'geometry.dart';
... ...
... ... @@ -20,6 +20,7 @@ import 'package:meta/meta.dart';
import 'package:pdf/pdf.dart';
import 'package:vector_math/vector_math_64.dart';
import 'box_border.dart';
import 'container.dart';
import 'decoration.dart';
import 'flex.dart';
... ... @@ -55,32 +56,93 @@ enum TableCellVerticalAlignment { bottom, middle, top, full }
enum TableWidth { min, max }
class TableBorder extends BoxBorder {
const TableBorder(
class TableBorder extends Border {
/// Creates a border for a table.
@Deprecated('Use TableBorder.ex instead')
TableBorder(
{bool left = true,
bool top = true,
bool right = true,
bool bottom = true,
this.horizontalInside = true,
this.verticalInside = true,
bool horizontalInside = true,
bool verticalInside = true,
PdfColor color = PdfColors.black,
double width = 1.0})
: super(
left: left,
top: top,
right: right,
bottom: bottom,
: horizontalInside = BorderSide(
color: color,
width: width);
width: width,
style: horizontalInside ? BorderStyle.solid : BorderStyle.none),
verticalInside = BorderSide(
color: color,
width: width,
style: verticalInside ? BorderStyle.solid : BorderStyle.none),
super(
top: BorderSide(
color: color,
width: width,
style: top ? BorderStyle.solid : BorderStyle.none),
bottom: BorderSide(
color: color,
width: width,
style: bottom ? BorderStyle.solid : BorderStyle.none),
left: BorderSide(
color: color,
width: width,
style: left ? BorderStyle.solid : BorderStyle.none),
right: BorderSide(
color: color,
width: width,
style: right ? BorderStyle.solid : BorderStyle.none));
/// Creates a border for a table.
const TableBorder.ex({
BorderSide left = BorderSide.none,
BorderSide top = BorderSide.none,
BorderSide right = BorderSide.none,
BorderSide bottom = BorderSide.none,
this.horizontalInside = BorderSide.none,
this.verticalInside = BorderSide.none,
}) : super(top: top, bottom: bottom, left: left, right: right);
/// A uniform border with all sides the same color and width.
factory TableBorder.all({
PdfColor color = PdfColors.black,
double width = 1.0,
BorderStyle style = BorderStyle.solid,
}) {
final side = BorderSide(color: color, width: width, style: style);
return TableBorder.ex(
top: side,
right: side,
bottom: side,
left: side,
horizontalInside: side,
verticalInside: side);
}
/// Creates a border for a table where all the interior sides use the same styling and all the exterior sides use the same styling.
factory TableBorder.symmetric({
BorderSide inside = BorderSide.none,
BorderSide outside = BorderSide.none,
}) {
return TableBorder.ex(
top: outside,
right: outside,
bottom: outside,
left: outside,
horizontalInside: inside,
verticalInside: inside,
);
}
final bool horizontalInside;
final bool verticalInside;
final BorderSide horizontalInside;
final BorderSide verticalInside;
void paint(Context context, PdfRect box,
void paintTable(Context context, PdfRect box,
[List<double> widths, List<double> heights]) {
super.paintRect(context, box);
super.paint(context, box);
if (verticalInside) {
if (verticalInside.style != BorderStyle.none) {
var offset = box.x;
for (var width in widths.sublist(0, widths.length - 1)) {
offset += width;
... ... @@ -90,7 +152,7 @@ class TableBorder extends BoxBorder {
context.canvas.strokePath();
}
if (horizontalInside) {
if (horizontalInside.style != BorderStyle.none) {
var offset = box.top;
for (var height in heights.sublist(0, heights.length - 1)) {
offset -= height;
... ... @@ -234,7 +296,14 @@ class Table extends Widget implements SpanningWidget {
Map<int, Alignment> headerAlignments,
TextStyle headerStyle,
OnCellFormat headerFormat,
TableBorder border = const TableBorder(),
TableBorder border = const TableBorder.ex(
left: BorderSide(),
right: BorderSide(),
top: BorderSide(),
bottom: BorderSide(),
horizontalInside: BorderSide(),
verticalInside: BorderSide(),
),
Map<int, TableColumnWidth> columnWidths,
TableColumnWidth defaultColumnWidth = const IntrinsicColumnWidth(),
TableWidth tableWidth = TableWidth.max,
... ... @@ -617,7 +686,7 @@ class Table extends Widget implements SpanningWidget {
context.canvas.restoreContext();
if (border != null) {
border.paint(context, box, _widths, _heights);
border.paintTable(context, box, _widths, _heights);
}
}
... ...
... ... @@ -80,7 +80,7 @@ void main() {
pdf.addPage(Page(
build: (Context context) => Table(
children: buildTable(context: context, count: 20),
border: const TableBorder(),
border: TableBorder.all(),
tableWidth: TableWidth.max,
),
));
... ... @@ -91,7 +91,7 @@ void main() {
build: (Context context) => <Widget>[
Table(
children: buildTable(context: context, count: 200),
border: const TableBorder(),
border: TableBorder.all(),
tableWidth: TableWidth.max,
),
]));
... ... @@ -103,7 +103,7 @@ void main() {
Table(
children: buildTable(
context: context, count: 200, repeatHeader: true),
border: const TableBorder(),
border: TableBorder.all(),
tableWidth: TableWidth.max,
),
]));
... ... @@ -115,7 +115,7 @@ void main() {
SizedBox(height: 710),
Table(
children: buildTable(context: context, count: 4),
border: const TableBorder(),
border: TableBorder.all(),
tableWidth: TableWidth.max,
),
]));
... ... @@ -128,7 +128,7 @@ void main() {
Table(
children:
buildTable(context: context, count: 4, repeatHeader: true),
border: const TableBorder(),
border: TableBorder.all(),
tableWidth: TableWidth.max,
),
]));
... ... @@ -138,7 +138,7 @@ void main() {
pdf.addPage(Page(
build: (Context context) => Table(
children: buildTable(context: context, count: 20),
border: const TableBorder(),
border: TableBorder.all(),
columnWidths: <int, TableColumnWidth>{
0: const FixedColumnWidth(80),
1: const FlexColumnWidth(2),
... ... @@ -218,12 +218,13 @@ void main() {
fontWeight: FontWeight.bold,
),
rowDecoration: const BoxDecoration(
border: BoxBorder(
bottom: true,
border: Border(
bottom: BorderSide(
color: PdfColors.indigo,
width: .5,
),
),
),
headers: <dynamic>['One', 'Two', 'Three'],
data: <List<dynamic>>[
<dynamic>[1, 2, 3],
... ...
... ... @@ -108,7 +108,7 @@ void main() {
),
Container(
decoration:
const BoxDecoration(border: BoxBorder(top: true, width: 1)),
const BoxDecoration(border: Border(top: BorderSide())),
child: Text(
"That's all Folks!",
tightBounds: true,
... ...
No preview for this file type
No preview for this file type