David PHAM-VAN

Convert Flex to a SpanningWidget

... ... @@ -11,6 +11,7 @@
- Add more font drawing options
- Add Opacity Widget
- Fix Text height with TrueType fonts
- Convert Flex to a SpanningWidget
## 1.4.1
... ...
... ... @@ -56,7 +56,28 @@ enum VerticalDirection {
typedef _ChildSizingFunction = double Function(Widget child, double extent);
class Flex extends MultiChildWidget {
class _FlexContext extends WidgetContext {
int firstChild = 0;
int lastChild = 0;
@override
void apply(WidgetContext other) {
if (other is _FlexContext) {
firstChild = other.firstChild;
lastChild = other.lastChild;
}
}
@override
WidgetContext clone() {
return _FlexContext()..apply(this);
}
@override
String toString() => '$runtimeType first:$firstChild last:$lastChild';
}
class Flex extends MultiChildWidget implements SpanningWidget {
Flex({
@required this.direction,
this.mainAxisAlignment = MainAxisAlignment.start,
... ... @@ -80,6 +101,8 @@ class Flex extends MultiChildWidget {
final VerticalDirection verticalDirection;
final _FlexContext _context = _FlexContext();
double _getIntrinsicSize(
{Axis sizingDirection,
double
... ... @@ -209,7 +232,6 @@ class Flex extends MultiChildWidget {
{bool parentUsesSize = false}) {
// Determine used flex factor, size inflexible items, calculate free space.
int totalFlex = 0;
final int totalChildren = children.length;
Widget lastFlexChild;
assert(constraints != null);
final double maxMainSize = direction == Axis.horizontal
... ... @@ -219,8 +241,9 @@ class Flex extends MultiChildWidget {
double crossSize = 0;
double allocatedSize = 0; // Sum of the sizes of the non-flexible children.
int index = _context.firstChild;
for (Widget child in children) {
for (Widget child in children.sublist(_context.firstChild)) {
final int flex = child is Flexible ? child.flex : 0;
final FlexFit fit = child is Flexible ? child.fit : FlexFit.loose;
if (flex > 0) {
... ... @@ -266,9 +289,16 @@ class Flex extends MultiChildWidget {
assert(child.box != null);
allocatedSize += _getMainSize(child);
crossSize = math.max(crossSize, _getCrossSize(child));
if (direction == Axis.vertical &&
allocatedSize > constraints.maxHeight) {
break;
}
}
lastFlexChild = child;
index++;
}
_context.lastChild = index;
final int totalChildren = _context.lastChild - _context.firstChild;
// Distribute free space to flexible children, and determine baseline.
final double freeSpace =
... ... @@ -409,7 +439,9 @@ class Flex extends MultiChildWidget {
direction == Axis.vertical);
double childMainPosition =
flipMainAxis ? actualSize - leadingSpace : leadingSpace;
for (Widget child in children) {
for (Widget child
in children.sublist(_context.firstChild, _context.lastChild)) {
double childCrossPosition;
switch (crossAxisAlignment) {
case CrossAxisAlignment.start:
... ... @@ -458,11 +490,31 @@ class Flex extends MultiChildWidget {
context.canvas
..saveContext()
..setTransform(mat);
for (Widget child in children) {
for (Widget child
in children.sublist(_context.firstChild, _context.lastChild)) {
child.paint(context);
}
context.canvas.restoreContext();
}
@override
bool get canSpan => direction == Axis.vertical;
@override
bool get hasMoreWidgets => true;
@override
void restoreContext(WidgetContext context) {
if (context is _FlexContext) {
_context.firstChild = context.lastChild;
}
}
@override
WidgetContext saveContext() {
return _context;
}
}
class Row extends Flex {
... ...
... ... @@ -328,6 +328,9 @@ class GridView extends MultiChildWidget implements SpanningWidget {
bool get canSpan => true;
@override
bool get hasMoreWidgets => true;
@override
void restoreContext(WidgetContext context) {
if (context is _GridViewContext) {
_context.firstChild = context.lastChild;
... ...
... ... @@ -25,7 +25,9 @@ abstract class WidgetContext {
}
abstract class SpanningWidget extends Widget {
bool get canSpan => false;
bool get canSpan;
bool get hasMoreWidgets;
/// Get unmodified mutable context object
@protected
... ... @@ -170,6 +172,10 @@ class MultiPage extends Page {
while (index < children.length) {
final Widget child = children[index];
bool canSpan = false;
if (child is SpanningWidget) {
canSpan = child.canSpan;
}
assert(() {
// Detect too big widgets
... ... @@ -226,7 +232,7 @@ class MultiPage extends Page {
}
// If we are processing a multi-page widget, we restore its context
if (widgetContext != null && child is SpanningWidget) {
if (widgetContext != null && canSpan && child is SpanningWidget) {
child.restoreContext(widgetContext);
widgetContext = null;
}
... ... @@ -238,14 +244,13 @@ class MultiPage extends Page {
if (offsetStart - child.box.height < offsetEnd) {
// If it is not a multi-page widget and its height
// is smaller than a full new page, we schedule a new page creation
if (child.box.height <= pageHeight - pageHeightMargin &&
!(child is SpanningWidget)) {
if (child.box.height <= pageHeight - pageHeightMargin && !canSpan) {
context = null;
continue;
}
// Else we crash if the widget is too big and cannot be splitted
if (!(child is SpanningWidget)) {
if (!canSpan) {
throw Exception(
'Widget won\'t fit into the page as its height (${child.box.height}) '
'exceed a page height (${pageHeight - pageHeightMargin}). '
... ... @@ -270,7 +275,7 @@ class MultiPage extends Page {
);
// Has it finished spanning?
if (!span.canSpan) {
if (!span.hasMoreWidgets) {
sameCount = 0;
index++;
}
... ... @@ -286,8 +291,9 @@ class MultiPage extends Page {
x: _margin.left,
y: offsetStart - child.box.height,
constraints: constraints,
widgetContext:
child is SpanningWidget ? child.saveContext().clone() : null,
widgetContext: child is SpanningWidget && canSpan
? child.saveContext().clone()
: null,
),
);
... ... @@ -315,7 +321,7 @@ class MultiPage extends Page {
for (_MultiPageWidget widget in page.widgets) {
final Widget child = widget.child;
if (child is SpanningWidget) {
if (child is SpanningWidget && child.canSpan) {
final WidgetContext context = child.saveContext();
context.apply(widget.widgetContext);
}
... ...
... ... @@ -224,6 +224,9 @@ class Table extends Widget implements SpanningWidget {
@override
bool get canSpan => true;
@override
bool get hasMoreWidgets => true;
/// The rows of the table.
final List<TableRow> children;
... ...
... ... @@ -109,7 +109,10 @@ class Wrap extends MultiChildWidget implements SpanningWidget {
bool get textDirection => false;
@override
bool get canSpan => _context.lastChild < children.length;
bool get canSpan => true;
@override
bool get hasMoreWidgets => _context.lastChild < children.length;
final _WrapContext _context = _WrapContext();
... ...