| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:sky' as sky; |
| import 'box.dart'; |
| import 'node.dart'; |
| |
| class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> { |
| int flex; |
| void merge(FlexBoxParentData other) { |
| if (other.flex != null) |
| flex = other.flex; |
| super.merge(other); |
| } |
| } |
| |
| enum FlexDirection { Horizontal, Vertical } |
| |
| class RenderFlex extends RenderBox with ContainerRenderNodeMixin<RenderBox, FlexBoxParentData>, |
| RenderBoxContainerDefaultsMixin<RenderBox, FlexBoxParentData> { |
| // lays out RenderBox children using flexible layout |
| |
| RenderFlex({ |
| FlexDirection direction: FlexDirection.Horizontal |
| }) : _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(); |
| } |
| |
| bool get sizedByParent => true; |
| void performResize() { |
| size = constraints.constrain(new sky.Size(constraints.maxWidth, constraints.maxHeight)); |
| assert(size.height < double.INFINITY); |
| assert(size.width < double.INFINITY); |
| } |
| |
| int _getFlex(RenderBox child) { |
| assert(child.parentData is FlexBoxParentData); |
| return child.parentData.flex != null ? child.parentData.flex : 0; |
| } |
| |
| void performLayout() { |
| // 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 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) { |
| totalFlex += child.parentData.flex; |
| } else { |
| BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight, |
| maxWidth: constraints.maxWidth); |
| child.layout(innerConstraints, parentUsesSize: true); |
| freeSpace -= (_direction == FlexDirection.Horizontal) ? child.size.width : child.size.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 innerConstraints; |
| switch (_direction) { |
| case FlexDirection.Horizontal: |
| innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight, |
| minWidth: spaceForChild, |
| maxWidth: spaceForChild); |
| break; |
| case FlexDirection.Vertical: |
| innerConstraints = new BoxConstraints(minHeight: spaceForChild, |
| maxHeight: spaceForChild, |
| maxWidth: constraints.maxWidth); |
| break; |
| } |
| child.layout(innerConstraints, parentUsesSize: true); |
| } |
| |
| // For now, center the flex items in the cross direction |
| switch (_direction) { |
| case FlexDirection.Horizontal: |
| child.parentData.position = new sky.Point(usedSpace, size.height / 2.0 - child.size.height / 2.0); |
| usedSpace += child.size.width; |
| break; |
| case FlexDirection.Vertical: |
| child.parentData.position = new sky.Point(size.width / 2.0 - child.size.width / 2.0, usedSpace); |
| usedSpace += child.size.height; |
| break; |
| } |
| child = child.parentData.nextSibling; |
| } |
| } |
| |
| void hitTestChildren(HitTestResult result, { sky.Point position }) { |
| defaultHitTestChildren(result, position: position); |
| } |
| |
| void paint(RenderNodeDisplayList canvas) { |
| defaultPaint(canvas); |
| } |
| } |