| Index: sky/sdk/lib/framework/layout2.dart
|
| diff --git a/sky/sdk/lib/framework/layout2.dart b/sky/sdk/lib/framework/layout2.dart
|
| index f0d0e522fa294d3405d5baa7df0e78ea1f46459a..e7e0b6d9a17a0523c52429a29db24b62d12629d2 100644
|
| --- a/sky/sdk/lib/framework/layout2.dart
|
| +++ b/sky/sdk/lib/framework/layout2.dart
|
| @@ -240,7 +240,10 @@ abstract class RenderNode extends AbstractNode {
|
| // following (with the signature being whatever passes for coordinates
|
| // for this particular class):
|
| // bool hitTest(HitTestResult result, { double x, double y }) {
|
| - // // If (x,y) is not inside this node, then return false.
|
| + // // If (x,y) is not inside this node, then return false. (You
|
| + // // can assume that the given coordinate is inside your
|
| + // // dimensions. You only need to check this if you're an
|
| + // // irregular shape, e.g. if you have a hole.)
|
| // // Otherwise:
|
| // // For each child that intersects x,y, in z-order starting from the top,
|
| // // call hitTest() for that child, passing it /result/, and the coordinates
|
| @@ -262,6 +265,9 @@ class HitTestResult {
|
| }
|
| }
|
|
|
| +
|
| +// GENERIC MIXIN FOR RENDER NODES WITH ONE CHILD
|
| +
|
| abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> {
|
| ChildType _child;
|
| ChildType get child => _child;
|
| @@ -275,7 +281,8 @@ abstract class RenderNodeWithChildMixin<ChildType extends RenderNode> {
|
| }
|
| }
|
|
|
| -// GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN
|
| +
|
| +// GENERIC MIXIN FOR RENDER NODES WITH A LIST OF CHILDREN
|
|
|
| abstract class ContainerParentDataMixin<ChildType extends RenderNode> {
|
| ChildType previousSibling;
|
| @@ -430,6 +437,19 @@ abstract class ContainerRenderNodeMixin<ChildType extends RenderNode, ParentData
|
| // GENERIC BOX RENDERING
|
| // Anything that has a concept of x, y, width, height is going to derive from this
|
|
|
| +class EdgeDims {
|
| + // used for e.g. padding
|
| + const EdgeDims(this.top, this.right, this.bottom, this.left);
|
| + final double top;
|
| + final double right;
|
| + final double bottom;
|
| + final double left;
|
| + operator ==(EdgeDims other) => (top == other.top) ||
|
| + (right == other.right) ||
|
| + (bottom == other.bottom) ||
|
| + (left == other.left);
|
| +}
|
| +
|
| class BoxConstraints {
|
| const BoxConstraints({
|
| this.minWidth: 0.0,
|
| @@ -443,6 +463,16 @@ class BoxConstraints {
|
| minHeight = height,
|
| maxHeight = height;
|
|
|
| + BoxConstraints deflate(EdgeDims edges) {
|
| + assert(edges != null);
|
| + return new BoxConstraints(
|
| + minWidth: minWidth,
|
| + maxWidth: maxWidth - (edges.left + edges.right),
|
| + minHeight: minHeight,
|
| + maxHeight: maxHeight - (edges.top + edges.bottom)
|
| + );
|
| + }
|
| +
|
| final double minWidth;
|
| final double maxWidth;
|
| final double minHeight;
|
| @@ -500,8 +530,6 @@ abstract class RenderBox extends RenderNode {
|
| }
|
|
|
| bool hitTest(HitTestResult result, { double x, double y }) {
|
| - if (x < 0.0 || x >= width || y < 0.0 || y >= height)
|
| - return false;
|
| hitTestChildren(result, x: x, y: y);
|
| result.add(this);
|
| return true;
|
| @@ -512,6 +540,68 @@ abstract class RenderBox extends RenderNode {
|
| double height;
|
| }
|
|
|
| +class RenderPadding extends RenderBox with RenderNodeWithChildMixin<RenderBox> {
|
| +
|
| + RenderPadding(EdgeDims padding, RenderBox child) {
|
| + assert(padding != null);
|
| + this.padding = padding;
|
| + this.child = child;
|
| + }
|
| +
|
| + EdgeDims _padding;
|
| + EdgeDims get padding => _padding;
|
| + void set padding (EdgeDims value) {
|
| + assert(value != null);
|
| + if (_padding != value) {
|
| + _padding = value;
|
| + markNeedsLayout();
|
| + }
|
| + }
|
| +
|
| + BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) {
|
| + assert(padding != null);
|
| + constraints = constraints.deflate(padding);
|
| + if (child == null)
|
| + return super.getIntrinsicDimensions(constraints);
|
| + return child.getIntrinsicDimensions(constraints);
|
| + }
|
| +
|
| + void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
|
| + assert(padding != null);
|
| + constraints = constraints.deflate(padding);
|
| + if (child == null) {
|
| + width = constraints.constrainWidth(padding.left + padding.right);
|
| + height = constraints.constrainHeight(padding.top + padding.bottom);
|
| + return;
|
| + }
|
| + if (relayoutSubtreeRoot != null)
|
| + saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
|
| + else
|
| + relayoutSubtreeRoot = this;
|
| + child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot);
|
| + assert(child.parentData is BoxParentData);
|
| + child.parentData.x = padding.left;
|
| + child.parentData.y = padding.top;
|
| + width = constraints.constrainWidth(padding.left + child.width + padding.right);
|
| + height = constraints.constrainHeight(padding.top + child.height + padding.bottom);
|
| + }
|
| +
|
| + void paint(RenderNodeDisplayList canvas) {
|
| + if (child != null)
|
| + canvas.paintChild(child, child.parentData.x, child.parentData.y);
|
| + }
|
| +
|
| + void hitTestChildren(HitTestResult result, { double x, double y }) {
|
| + if (child != null) {
|
| + assert(child.parentData is BoxParentData);
|
| + if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) &&
|
| + (y >= child.parentData.y) && (y < child.parentData.y + child.height))
|
| + child.hitTest(result, x: x+child.parentData.x, y: y+child.parentData.y);
|
| + }
|
| + }
|
| +
|
| +}
|
| +
|
| // This must be immutable, because we won't notice when it changes
|
| class BoxDecoration {
|
| const BoxDecoration({
|
| @@ -613,12 +703,7 @@ class RenderView extends RenderNode with RenderNodeWithChildMixin<RenderBox> {
|
|
|
| void relayout() {
|
| if (child != null) {
|
| - child.layout(new BoxConstraints(
|
| - minWidth: width,
|
| - maxWidth: width,
|
| - minHeight: height,
|
| - maxHeight: height
|
| - ));
|
| + child.layout(new BoxConstraints.tight(width: width, height: height));
|
| assert(child.width == width);
|
| assert(child.height == height);
|
| }
|
| @@ -630,12 +715,8 @@ class RenderView extends RenderNode with RenderNodeWithChildMixin<RenderBox> {
|
| }
|
|
|
| bool hitTest(HitTestResult result, { double x, double y }) {
|
| - if (x < 0.0 || x >= width || y < 0.0 || y >= height)
|
| - return false;
|
| - if (child != null) {
|
| - if (x >= 0.0 && x < child.width && y >= 0.0 && y < child.height)
|
| - child.hitTest(result, x: x, y: y);
|
| - }
|
| + if (child != null && x >= 0.0 && x < child.width && y >= 0.0 && y < child.height)
|
| + child.hitTest(result, x: x, y: y);
|
| result.add(this);
|
| return true;
|
| }
|
| @@ -684,19 +765,6 @@ abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare
|
|
|
| // BLOCK LAYOUT MANAGER
|
|
|
| -class EdgeDims {
|
| - // used for e.g. padding
|
| - const EdgeDims(this.top, this.right, this.bottom, this.left);
|
| - final double top;
|
| - final double right;
|
| - final double bottom;
|
| - final double left;
|
| - operator ==(EdgeDims other) => (top == other.top) ||
|
| - (right == other.right) ||
|
| - (bottom == other.bottom) ||
|
| - (left == other.left);
|
| -}
|
| -
|
| class BlockParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> { }
|
|
|
| class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<RenderBox, BlockParentData>,
|
| @@ -706,19 +774,8 @@ class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende
|
| // sizes itself to the height of its child stack
|
|
|
| RenderBlock({
|
| - BoxDecoration decoration,
|
| - EdgeDims padding: const EdgeDims(0.0, 0.0, 0.0, 0.0)
|
| - }) : super(decoration), _padding = padding;
|
| -
|
| - EdgeDims _padding;
|
| - EdgeDims get padding => _padding;
|
| - void set padding (EdgeDims value) {
|
| - assert(value != null);
|
| - if (_padding != value) {
|
| - _padding = value;
|
| - markNeedsLayout();
|
| - }
|
| - }
|
| + BoxDecoration decoration
|
| + }) : super(decoration);
|
|
|
| void setParentData(RenderBox child) {
|
| if (child.parentData is! BlockParentData)
|
| @@ -731,10 +788,10 @@ class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende
|
| // dimensions and nothing else (e.g. don't calculate hypothetical
|
| // child positions if they're not needed to determine dimensions)
|
| BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) {
|
| - double outerHeight = _padding.top + _padding.bottom;
|
| + double outerHeight = 0.0;
|
| double outerWidth = constraints.constrainWidth(constraints.maxWidth);
|
| assert(outerWidth < double.INFINITY);
|
| - double innerWidth = outerWidth - (_padding.left + _padding.right);
|
| + double innerWidth = outerWidth;
|
| RenderBox child = firstChild;
|
| BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth,
|
| maxWidth: innerWidth);
|
| @@ -766,19 +823,19 @@ class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende
|
|
|
| void internalLayout(RenderNode relayoutSubtreeRoot) {
|
| assert(_constraints != null);
|
| - double y = _padding.top;
|
| - double innerWidth = width - (_padding.left + _padding.right);
|
| + double y = 0.0;
|
| + double innerWidth = width;
|
| RenderBox child = firstChild;
|
| while (child != null) {
|
| child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth),
|
| relayoutSubtreeRoot: relayoutSubtreeRoot);
|
| assert(child.parentData is BlockParentData);
|
| - child.parentData.x = _padding.left;
|
| + child.parentData.x = 0.0;
|
| child.parentData.y = y;
|
| y += child.height;
|
| child = child.parentData.nextSibling;
|
| }
|
| - height = _constraints.constrainHeight(y + _padding.bottom);
|
| + height = _constraints.constrainHeight(y);
|
| layoutDone();
|
| }
|
|
|
|
|