| Index: sky/sdk/lib/framework/layout2.dart
|
| diff --git a/sky/sdk/lib/framework/layout2.dart b/sky/sdk/lib/framework/layout2.dart
|
| index 0284dc845acb6614d0ece7aed9ff830258694cbe..4980f4cc6a897f118cc03aaa42b1e23561da865c 100644
|
| --- a/sky/sdk/lib/framework/layout2.dart
|
| +++ b/sky/sdk/lib/framework/layout2.dart
|
| @@ -221,6 +221,7 @@ abstract class RenderNode extends AbstractNode {
|
| bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
|
| // override this if you have children, to hand it to the appropriate child
|
| // override this if you want to do anything with the pointer event
|
| + return false;
|
| }
|
|
|
|
|
| @@ -425,10 +426,9 @@ class BoxDimensions {
|
| const BoxDimensions({this.width, this.height});
|
|
|
| BoxDimensions.withConstraints(
|
| - BoxConstraints constraints, {double width: 0.0, double height: 0.0}) {
|
| - this.width = constraints.constrainWidth(width);
|
| - this.height = constraints.constrainHeight(height);
|
| - }
|
| + BoxConstraints constraints, {double width: 0.0, double height: 0.0})
|
| + : width = constraints.constrainWidth(width),
|
| + height = constraints.constrainHeight(height);
|
|
|
| final double width;
|
| final double height;
|
| @@ -580,6 +580,33 @@ class RenderView extends RenderNode {
|
|
|
| }
|
|
|
| +// DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS
|
| +abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, ParentDataType extends ContainerParentDataMixin<ChildType>> implements ContainerRenderNodeMixin<ChildType, ParentDataType> {
|
| + bool defaultHandlePointer(sky.PointerEvent event, double x, double y) {
|
| + // the x, y parameters have the top left of the node's box as the origin
|
| + ChildType child = lastChild;
|
| + while (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)) {
|
| + if (child.handlePointer(event, x: x-child.parentData.x, y: y-child.parentData.y))
|
| + return true;
|
| + break;
|
| + }
|
| + child = child.parentData.previousSibling;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + void defaultPaint(RenderNodeDisplayList canvas) {
|
| + RenderBox child = firstChild;
|
| + while (child != null) {
|
| + assert(child.parentData is BoxParentData);
|
| + canvas.paintChild(child, child.parentData.x, child.parentData.y);
|
| + child = child.parentData.nextSibling;
|
| + }
|
| + }
|
| +}
|
|
|
| // BLOCK LAYOUT MANAGER
|
|
|
| @@ -598,7 +625,8 @@ class EdgeDims {
|
|
|
| class BlockParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> { }
|
|
|
| -class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<RenderBox, BlockParentData> {
|
| +class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<RenderBox, BlockParentData>,
|
| + RenderBoxContainerDefaultsMixin<RenderBox, BlockParentData> {
|
| // lays out RenderBox children in a vertical stack
|
| // uses the maximum width provided by the parent
|
| // sizes itself to the height of its child stack
|
| @@ -634,10 +662,10 @@ class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende
|
| assert(outerWidth < double.INFINITY);
|
| double innerWidth = outerWidth - (_padding.left + _padding.right);
|
| RenderBox child = _firstChild;
|
| - BoxConstraints constraints = new BoxConstraints(minWidth: innerWidth,
|
| - maxWidth: innerWidth);
|
| + BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth,
|
| + maxWidth: innerWidth);
|
| while (child != null) {
|
| - outerHeight += child.getIntrinsicDimensions(constraints).height;
|
| + outerHeight += child.getIntrinsicDimensions(innerConstraints).height;
|
| assert(child.parentData is BlockParentData);
|
| child = child.parentData.nextSibling;
|
| }
|
| @@ -683,34 +711,19 @@ class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende
|
| }
|
|
|
| bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
|
| - // the x, y parameters have the top left of the node's box as the origin
|
| - RenderBox child = _lastChild;
|
| - while (child != null) {
|
| - assert(child.parentData is BlockParentData);
|
| - if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) &&
|
| - (y >= child.parentData.y) && (y < child.parentData.y + child.height)) {
|
| - if (child.handlePointer(event, x: x-child.parentData.x, y: y-child.parentData.y))
|
| - return true;
|
| - break;
|
| - }
|
| - child = child.parentData.previousSibling;
|
| - }
|
| - return super.handlePointer(event, x: x, y: y);
|
| + return defaultHandlePointer(event, x, y) || super.handlePointer(event, x: x, y: y);
|
| }
|
|
|
| void paint(RenderNodeDisplayList canvas) {
|
| super.paint(canvas);
|
| - RenderBox child = _firstChild;
|
| - while (child != null) {
|
| - assert(child.parentData is BlockParentData);
|
| - canvas.paintChild(child, child.parentData.x, child.parentData.y);
|
| - child = child.parentData.nextSibling;
|
| - }
|
| + defaultPaint(canvas);
|
| }
|
|
|
| }
|
|
|
| -class FlexBoxParentData extends BoxParentData {
|
| +// FLEXBOX LAYOUT MANAGER
|
| +
|
| +class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> {
|
| int flex;
|
| void merge(FlexBoxParentData other) {
|
| if (other.flex != null)
|
| @@ -719,10 +732,127 @@ class FlexBoxParentData extends BoxParentData {
|
| }
|
| }
|
|
|
| -enum FlexDirection { Row, Column }
|
| +enum FlexDirection { Horizontal, Vertical }
|
| +
|
| +class RenderFlex extends RenderDecoratedBox with ContainerRenderNodeMixin<RenderBox, FlexBoxParentData>,
|
| + RenderBoxContainerDefaultsMixin<RenderBox, BlockParentData> {
|
| + // lays out RenderBox children using flexible layout
|
| +
|
| + RenderFlex({
|
| + BoxDecoration decoration,
|
| + FlexDirection direction: FlexDirection.Horizontal
|
| + }) : super(decoration), _direction = direction;
|
| +
|
| + FlexDirection _direction;
|
| + FlexDirection get direction => _direction;
|
| + void set direction (FlexDirection value) {
|
| + if (_direction != value) {
|
| + _direction = value;
|
| + markNeedsLayout();
|
| + }
|
| + }
|
| +
|
| + void setParentData(RenderBox child) {
|
| + if (child.parentData is! FlexBoxParentData)
|
| + child.parentData = new FlexBoxParentData();
|
| + }
|
| +
|
| + BoxConstraints _constraints; // value cached from parent for relayout call
|
| + void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
|
| + if (relayoutSubtreeRoot != null)
|
| + saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
|
| + relayoutSubtreeRoot = relayoutSubtreeRoot == null ? this : relayoutSubtreeRoot;
|
| + _constraints = constraints;
|
| + width = _constraints.constrainWidth(_constraints.maxWidth);
|
| + height = _constraints.constrainHeight(_constraints.maxHeight);
|
| + assert(height < double.INFINITY);
|
| + assert(width < double.INFINITY);
|
| + internalLayout(relayoutSubtreeRoot);
|
| + }
|
| +
|
| + void relayout() {
|
| + internalLayout(this);
|
| + }
|
| +
|
| + int _getFlex(RenderBox child) {
|
| + assert(child.parentData is FlexBoxParentData);
|
| + return (child.parentData.flex != null ? child.parentData.flex : 0);
|
| + }
|
| +
|
| + void internalLayout(RenderNode relayoutSubtreeRoot) {
|
| + // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexible Lengths
|
| + // Steps 1-3. Determine used flex factor, size inflexible items, calculate free space
|
| + int numFlexibleChildren = 0;
|
| + int totalFlex = 0;
|
| + assert(_constraints != null);
|
| + double freeSpace = (_direction == FlexDirection.Horizontal) ? _constraints.maxWidth : _constraints.maxHeight;
|
| + RenderBox child = _firstChild;
|
| + while (child != null) {
|
| + int flex = _getFlex(child);
|
| + if (flex > 0) {
|
| + numFlexibleChildren++;
|
| + totalFlex += child.parentData.flex;
|
| + } else {
|
| + BoxConstraints constraints = new BoxConstraints(maxHeight: _constraints.maxHeight,
|
| + maxWidth: _constraints.maxWidth);
|
| + child.layout(constraints,
|
| + relayoutSubtreeRoot: relayoutSubtreeRoot);
|
| + freeSpace -= (_direction == FlexDirection.Horizontal) ? child.width : child.height;
|
| + }
|
| + child = child.parentData.nextSibling;
|
| + }
|
| +
|
| + // Steps 4-5. Distribute remaining space to flexible children.
|
| + double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0;
|
| + double usedSpace = 0.0;
|
| + child = _firstChild;
|
| + while (child != null) {
|
| + int flex = _getFlex(child);
|
| + if (flex > 0) {
|
| + double spaceForChild = spacePerFlex * flex;
|
| + BoxConstraints constraints;
|
| + switch (_direction) {
|
| + case FlexDirection.Horizontal:
|
| + constraints = new BoxConstraints(maxHeight: _constraints.maxHeight,
|
| + minWidth: spaceForChild,
|
| + maxWidth: spaceForChild);
|
| + break;
|
| + case FlexDirection.Vertical:
|
| + constraints = new BoxConstraints(minHeight: spaceForChild,
|
| + maxHeight: spaceForChild,
|
| + maxWidth: _constraints.maxWidth);
|
| + break;
|
| + }
|
| + child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot);
|
| + }
|
|
|
| -// TODO(ianh): FlexBox
|
| + // For now, center the flex items in the cross direction
|
| + switch (_direction) {
|
| + case FlexDirection.Horizontal:
|
| + child.parentData.x = usedSpace;
|
| + usedSpace += child.width;
|
| + child.parentData.y = height / 2 - child.height / 2;
|
| + break;
|
| + case FlexDirection.Vertical:
|
| + child.parentData.y = usedSpace;
|
| + usedSpace += child.height;
|
| + child.parentData.x = width / 2 - child.width / 2;
|
| + break;
|
| + }
|
| + child = child.parentData.nextSibling;
|
| + }
|
| + layoutDone();
|
| + }
|
| +
|
| + bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
|
| + return defaultHandlePointer(event, x, y) || super.handlePointer(event, x: x, y: y);
|
| + }
|
|
|
| + void paint(RenderNodeDisplayList canvas) {
|
| + super.paint(canvas);
|
| + defaultPaint(canvas);
|
| + }
|
| +}
|
|
|
| // SCAFFOLD LAYOUT MANAGER
|
|
|
|
|