Commit 6ea7ab89 authored by Ian Hickson's avatar Ian Hickson

Add a row decoration to RenderTable

This will let us draw in-row bottom borders and row-wide backgrounds,

both of which are necessary for Material data tables.
parent d748186c
...@@ -345,6 +345,8 @@ class RenderTable extends RenderBox { ...@@ -345,6 +345,8 @@ class RenderTable extends RenderBox {
Map<int, TableColumnWidth> columnWidths, Map<int, TableColumnWidth> columnWidths,
TableColumnWidth defaultColumnWidth: const FlexColumnWidth(1.0), TableColumnWidth defaultColumnWidth: const FlexColumnWidth(1.0),
TableBorder border, TableBorder border,
List<Decoration> rowDecorations,
Decoration defaultRowDecoration,
TableCellVerticalAlignment defaultVerticalAlignment: TableCellVerticalAlignment.top, TableCellVerticalAlignment defaultVerticalAlignment: TableCellVerticalAlignment.top,
TextBaseline textBaseline, TextBaseline textBaseline,
List<List<RenderBox>> children List<List<RenderBox>> children
...@@ -359,6 +361,7 @@ class RenderTable extends RenderBox { ...@@ -359,6 +361,7 @@ class RenderTable extends RenderBox {
_columnWidths = columnWidths ?? new HashMap<int, TableColumnWidth>(); _columnWidths = columnWidths ?? new HashMap<int, TableColumnWidth>();
_defaultColumnWidth = defaultColumnWidth; _defaultColumnWidth = defaultColumnWidth;
_border = border; _border = border;
this.rowDecorations = rowDecorations; // must use setter to initialize box painters
_defaultVerticalAlignment = defaultVerticalAlignment; _defaultVerticalAlignment = defaultVerticalAlignment;
_textBaseline = textBaseline; _textBaseline = textBaseline;
if (children != null) { if (children != null) {
...@@ -367,8 +370,6 @@ class RenderTable extends RenderBox { ...@@ -367,8 +370,6 @@ class RenderTable extends RenderBox {
} }
} }
// TODO(ianh): Add a 'decoration' field to the children's parent data, to paint on each cell.
// Children are stored in row-major order. // Children are stored in row-major order.
// _children.length must be rows * columns // _children.length must be rows * columns
List<RenderBox> _children = const <RenderBox>[]; List<RenderBox> _children = const <RenderBox>[];
...@@ -419,8 +420,8 @@ class RenderTable extends RenderBox { ...@@ -419,8 +420,8 @@ class RenderTable extends RenderBox {
markNeedsLayout(); markNeedsLayout();
} }
Map<int, TableColumnWidth> _columnWidths;
Map<int, TableColumnWidth> get columnWidths => new Map<int, TableColumnWidth>.unmodifiable(_columnWidths); Map<int, TableColumnWidth> get columnWidths => new Map<int, TableColumnWidth>.unmodifiable(_columnWidths);
Map<int, TableColumnWidth> _columnWidths;
void set columnWidths(Map<int, TableColumnWidth> value) { void set columnWidths(Map<int, TableColumnWidth> value) {
value ??= new HashMap<int, TableColumnWidth>(); value ??= new HashMap<int, TableColumnWidth>();
if (_columnWidths == value) if (_columnWidths == value)
...@@ -454,6 +455,38 @@ class RenderTable extends RenderBox { ...@@ -454,6 +455,38 @@ class RenderTable extends RenderBox {
_border = value; _border = value;
markNeedsPaint(); markNeedsPaint();
} }
List<Decoration> get rowDecorations => new List<Decoration>.unmodifiable(_rowDecorations ?? const <Decoration>[]);
List<Decoration> _rowDecorations;
List<BoxPainter> _rowDecorationPainters;
void set rowDecorations(List<Decoration> value) {
if (_rowDecorations == value)
return;
_removeListenersIfNeeded();
_rowDecorations = value;
_rowDecorationPainters = _rowDecorations != null ? new List<BoxPainter>(_rowDecorations.length) : null;
_addListenersIfNeeded();
}
void _removeListenersIfNeeded() {
Set<Decoration> visitedDecorations = new Set<Decoration>();
if (_rowDecorations != null && attached) {
for (Decoration decoration in _rowDecorations) {
if (decoration != null && decoration.needsListeners && visitedDecorations.add(decoration))
decoration.removeChangeListener(markNeedsPaint);
}
}
}
void _addListenersIfNeeded() {
Set<Decoration> visitedDecorations = new Set<Decoration>();
if (_rowDecorations != null && attached) {
for (Decoration decoration in _rowDecorations) {
if (decoration != null && decoration.needsListeners && visitedDecorations.add(decoration))
decoration.addChangeListener(markNeedsPaint);
}
}
}
TableCellVerticalAlignment get defaultVerticalAlignment => _defaultVerticalAlignment; TableCellVerticalAlignment get defaultVerticalAlignment => _defaultVerticalAlignment;
TableCellVerticalAlignment _defaultVerticalAlignment; TableCellVerticalAlignment _defaultVerticalAlignment;
...@@ -581,13 +614,15 @@ class RenderTable extends RenderBox { ...@@ -581,13 +614,15 @@ class RenderTable extends RenderBox {
super.attach(owner); super.attach(owner);
for (RenderBox child in _children) for (RenderBox child in _children)
child?.attach(owner); child?.attach(owner);
_addListenersIfNeeded();
} }
@override @override
void detach() { void detach() {
super.detach(); _removeListenersIfNeeded();
for (RenderBox child in _children) for (RenderBox child in _children)
child?.detach(); child?.detach();
super.detach();
} }
@override @override
...@@ -823,8 +858,9 @@ class RenderTable extends RenderBox { ...@@ -823,8 +858,9 @@ class RenderTable extends RenderBox {
} }
rowTop += rowHeight; rowTop += rowHeight;
} }
_rowTops.add(rowTop);
size = constraints.constrain(new Size(positions.last + widths.last, rowTop)); size = constraints.constrain(new Size(positions.last + widths.last, rowTop));
assert(_rowTops.length == rows); assert(_rowTops.length == rows + 1);
} }
@override @override
...@@ -845,10 +881,25 @@ class RenderTable extends RenderBox { ...@@ -845,10 +881,25 @@ class RenderTable extends RenderBox {
@override @override
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
Canvas canvas;
assert(_children.length == rows * columns); assert(_children.length == rows * columns);
if (rows * columns == 0) if (rows * columns == 0)
return; return;
assert(_rowTops.length == rows); assert(_rowTops.length == rows + 1);
canvas = context.canvas;
if (_rowDecorations != null) {
for (int y = 0; y < rows; y += 1) {
if (_rowDecorations.length <= y)
break;
_rowDecorationPainters[y] ??= _rowDecorations[y].createBoxPainter();
_rowDecorationPainters[y].paint(canvas, new Rect.fromLTRB(
offset.dx,
offset.dy + _rowTops[y],
offset.dx + size.width,
offset.dy + _rowTops[y+1]
));
}
}
for (int index = 0; index < _children.length; index += 1) { for (int index = 0; index < _children.length; index += 1) {
RenderBox child = _children[index]; RenderBox child = _children[index];
if (child != null) { if (child != null) {
...@@ -856,9 +907,8 @@ class RenderTable extends RenderBox { ...@@ -856,9 +907,8 @@ class RenderTable extends RenderBox {
context.paintChild(child, childParentData.offset + offset); context.paintChild(child, childParentData.offset + offset);
} }
} }
canvas = context.canvas;
Rect bounds = offset & size; Rect bounds = offset & size;
Canvas canvas = context.canvas;
canvas.saveLayer(bounds, new Paint());
if (border != null) { if (border != null) {
switch (border.verticalInside.style) { switch (border.verticalInside.style) {
case BorderStyle.solid: case BorderStyle.solid:
...@@ -892,7 +942,6 @@ class RenderTable extends RenderBox { ...@@ -892,7 +942,6 @@ class RenderTable extends RenderBox {
} }
border.paint(canvas, bounds); border.paint(canvas, bounds);
} }
canvas.restore();
} }
@override @override
......
...@@ -21,8 +21,9 @@ export 'package:flutter/rendering.dart' show ...@@ -21,8 +21,9 @@ export 'package:flutter/rendering.dart' show
TableColumnWidth; TableColumnWidth;
class TableRow { class TableRow {
const TableRow({ this.key, this.children }); const TableRow({ this.key, this.decoration, this.children });
final LocalKey key; final LocalKey key;
final Decoration decoration;
final List<Widget> children; final List<Widget> children;
} }
...@@ -39,13 +40,15 @@ class _TableElementRow { ...@@ -39,13 +40,15 @@ class _TableElementRow {
class Table extends RenderObjectWidget { class Table extends RenderObjectWidget {
Table({ Table({
Key key, Key key,
this.children: const <TableRow>[], List<TableRow> children: const <TableRow>[],
this.columnWidths, this.columnWidths,
this.defaultColumnWidth: const FlexColumnWidth(1.0), this.defaultColumnWidth: const FlexColumnWidth(1.0),
this.border, this.border,
this.defaultVerticalAlignment: TableCellVerticalAlignment.top, this.defaultVerticalAlignment: TableCellVerticalAlignment.top,
this.textBaseline this.textBaseline
}) : super(key: key) { }) : children = children,
_rowDecorations = children.map/*<Decoration>*/((TableRow row) => row.decoration).toList(),
super(key: key) {
assert(children != null); assert(children != null);
assert(defaultColumnWidth != null); assert(defaultColumnWidth != null);
assert(defaultVerticalAlignment != null); assert(defaultVerticalAlignment != null);
...@@ -63,6 +66,8 @@ class Table extends RenderObjectWidget { ...@@ -63,6 +66,8 @@ class Table extends RenderObjectWidget {
final TableCellVerticalAlignment defaultVerticalAlignment; final TableCellVerticalAlignment defaultVerticalAlignment;
final TextBaseline textBaseline; final TextBaseline textBaseline;
final List<Decoration> _rowDecorations;
@override @override
_TableElement createElement() => new _TableElement(this); _TableElement createElement() => new _TableElement(this);
...@@ -74,6 +79,7 @@ class Table extends RenderObjectWidget { ...@@ -74,6 +79,7 @@ class Table extends RenderObjectWidget {
columnWidths: columnWidths, columnWidths: columnWidths,
defaultColumnWidth: defaultColumnWidth, defaultColumnWidth: defaultColumnWidth,
border: border, border: border,
rowDecorations: _rowDecorations,
defaultVerticalAlignment: defaultVerticalAlignment, defaultVerticalAlignment: defaultVerticalAlignment,
textBaseline: textBaseline textBaseline: textBaseline
); );
...@@ -87,6 +93,7 @@ class Table extends RenderObjectWidget { ...@@ -87,6 +93,7 @@ class Table extends RenderObjectWidget {
..columnWidths = columnWidths ..columnWidths = columnWidths
..defaultColumnWidth = defaultColumnWidth ..defaultColumnWidth = defaultColumnWidth
..border = border ..border = border
..rowDecorations = _rowDecorations
..defaultVerticalAlignment = defaultVerticalAlignment ..defaultVerticalAlignment = defaultVerticalAlignment
..textBaseline = textBaseline; ..textBaseline = textBaseline;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment