OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 import 'dart:math' as math; |
5 import 'box.dart'; | 6 import 'box.dart'; |
6 import 'object.dart'; | 7 import 'object.dart'; |
7 | 8 |
8 class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin<Rend
erBox> { | 9 class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin<Rend
erBox> { |
9 int flex; | 10 int flex; |
10 void merge(FlexBoxParentData other) { | 11 void merge(FlexBoxParentData other) { |
11 if (other.flex != null) | 12 if (other.flex != null) |
12 flex = other.flex; | 13 flex = other.flex; |
13 super.merge(other); | 14 super.merge(other); |
14 } | 15 } |
15 String toString() => '${super.toString()}; flex=$flex'; | 16 String toString() => '${super.toString()}; flex=$flex'; |
16 } | 17 } |
17 | 18 |
18 enum FlexDirection { horizontal, vertical } | 19 enum FlexDirection { horizontal, vertical } |
| 20 enum FlexJustifyContent { |
| 21 flexStart, |
| 22 flexEnd, |
| 23 center, |
| 24 spaceBetween, |
| 25 spaceAround, |
| 26 } |
19 | 27 |
20 class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
exBoxParentData>, | 28 class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
exBoxParentData>, |
21 RenderBoxContainerDefaultsMixin<RenderBo
x, FlexBoxParentData> { | 29 RenderBoxContainerDefaultsMixin<RenderBo
x, FlexBoxParentData> { |
22 // lays out RenderBox children using flexible layout | 30 // lays out RenderBox children using flexible layout |
23 | 31 |
24 RenderFlex({ | 32 RenderFlex({ |
25 FlexDirection direction: FlexDirection.horizontal | 33 FlexDirection direction: FlexDirection.horizontal, |
26 }) : _direction = direction; | 34 FlexJustifyContent justifyContent: FlexJustifyContent.flexStart |
| 35 }) : _direction = direction, _justifyContent = justifyContent; |
27 | 36 |
28 FlexDirection _direction; | 37 FlexDirection _direction; |
29 FlexDirection get direction => _direction; | 38 FlexDirection get direction => _direction; |
30 void set direction (FlexDirection value) { | 39 void set direction (FlexDirection value) { |
31 if (_direction != value) { | 40 if (_direction != value) { |
32 _direction = value; | 41 _direction = value; |
33 markNeedsLayout(); | 42 markNeedsLayout(); |
34 } | 43 } |
35 } | 44 } |
36 | 45 |
| 46 FlexJustifyContent _justifyContent; |
| 47 FlexJustifyContent get justifyContent => _justifyContent; |
| 48 void set justifyContent (FlexJustifyContent value) { |
| 49 if (_justifyContent != value) { |
| 50 _justifyContent = value; |
| 51 markNeedsLayout(); |
| 52 } |
| 53 } |
| 54 |
37 void setParentData(RenderBox child) { | 55 void setParentData(RenderBox child) { |
38 if (child.parentData is! FlexBoxParentData) | 56 if (child.parentData is! FlexBoxParentData) |
39 child.parentData = new FlexBoxParentData(); | 57 child.parentData = new FlexBoxParentData(); |
40 } | 58 } |
41 | 59 |
42 bool get sizedByParent => true; | 60 bool get sizedByParent => true; |
43 void performResize() { | 61 void performResize() { |
44 size = constraints.constrain(new Size(constraints.maxWidth, constraints.maxH
eight)); | 62 size = constraints.constrain(new Size(constraints.maxWidth, constraints.maxH
eight)); |
45 assert(size.height < double.INFINITY); | 63 assert(size.height < double.INFINITY); |
46 assert(size.width < double.INFINITY); | 64 assert(size.width < double.INFINITY); |
47 } | 65 } |
48 | 66 |
49 int _getFlex(RenderBox child) { | 67 int _getFlex(RenderBox child) { |
50 assert(child.parentData is FlexBoxParentData); | 68 assert(child.parentData is FlexBoxParentData); |
51 return child.parentData.flex != null ? child.parentData.flex : 0; | 69 return child.parentData.flex != null ? child.parentData.flex : 0; |
52 } | 70 } |
53 | 71 |
54 void performLayout() { | 72 void performLayout() { |
55 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib
le Lengths | 73 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib
le Lengths |
56 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f
ree space | 74 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f
ree space |
57 int totalFlex = 0; | 75 int totalFlex = 0; |
| 76 int totalChildren = 0; |
58 assert(constraints != null); | 77 assert(constraints != null); |
59 double freeSpace = (_direction == FlexDirection.horizontal) ? constraints.ma
xWidth : constraints.maxHeight; | 78 double freeSpace = (_direction == FlexDirection.horizontal) ? constraints.ma
xWidth : constraints.maxHeight; |
60 RenderBox child = firstChild; | 79 RenderBox child = firstChild; |
61 while (child != null) { | 80 while (child != null) { |
| 81 totalChildren++; |
62 int flex = _getFlex(child); | 82 int flex = _getFlex(child); |
63 if (flex > 0) { | 83 if (flex > 0) { |
64 totalFlex += child.parentData.flex; | 84 totalFlex += child.parentData.flex; |
65 } else { | 85 } else { |
66 BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constrai
nts.maxHeight, | 86 BoxConstraints innerConstraints = new BoxConstraints(maxHeight: constrai
nts.maxHeight, |
67 maxWidth: constrain
ts.maxWidth); | 87 maxWidth: constrain
ts.maxWidth); |
68 child.layout(innerConstraints, parentUsesSize: true); | 88 child.layout(innerConstraints, parentUsesSize: true); |
69 freeSpace -= (_direction == FlexDirection.horizontal) ? child.size.width
: child.size.height; | 89 freeSpace -= (_direction == FlexDirection.horizontal) ? child.size.width
: child.size.height; |
70 } | 90 } |
71 child = child.parentData.nextSibling; | 91 child = child.parentData.nextSibling; |
(...skipping 14 matching lines...) Expand all Loading... |
86 minWidth: spaceForChild, | 106 minWidth: spaceForChild, |
87 maxWidth: spaceForChild); | 107 maxWidth: spaceForChild); |
88 break; | 108 break; |
89 case FlexDirection.vertical: | 109 case FlexDirection.vertical: |
90 innerConstraints = new BoxConstraints(minHeight: spaceForChild, | 110 innerConstraints = new BoxConstraints(minHeight: spaceForChild, |
91 maxHeight: spaceForChild, | 111 maxHeight: spaceForChild, |
92 maxWidth: constraints.maxWidth
); | 112 maxWidth: constraints.maxWidth
); |
93 break; | 113 break; |
94 } | 114 } |
95 child.layout(innerConstraints, parentUsesSize: true); | 115 child.layout(innerConstraints, parentUsesSize: true); |
96 } | 116 usedSpace += _direction == FlexDirection.horizontal ? child.size.width :
child.size.height; |
97 | |
98 // For now, center the flex items in the cross direction | |
99 switch (_direction) { | |
100 case FlexDirection.horizontal: | |
101 child.parentData.position = new Point(usedSpace, size.height / 2.0 - c
hild.size.height / 2.0); | |
102 usedSpace += child.size.width; | |
103 break; | |
104 case FlexDirection.vertical: | |
105 child.parentData.position = new Point(size.width / 2.0 - child.size.wi
dth / 2.0, usedSpace); | |
106 usedSpace += child.size.height; | |
107 break; | |
108 } | 117 } |
109 child = child.parentData.nextSibling; | 118 child = child.parentData.nextSibling; |
110 } | 119 } |
| 120 |
| 121 // Section 8.2: Axis Alignment using the justify-content property |
| 122 double remainingSpace = math.max(0.0, freeSpace - usedSpace); |
| 123 double leadingSpace; |
| 124 double betweenSpace; |
| 125 child = firstChild; |
| 126 switch (_justifyContent) { |
| 127 case FlexJustifyContent.flexStart: |
| 128 leadingSpace = 0.0; |
| 129 betweenSpace = 0.0; |
| 130 break; |
| 131 case FlexJustifyContent.flexEnd: |
| 132 leadingSpace = remainingSpace; |
| 133 betweenSpace = 0.0; |
| 134 break; |
| 135 case FlexJustifyContent.center: |
| 136 leadingSpace = remainingSpace / 2.0; |
| 137 betweenSpace = 0.0; |
| 138 break; |
| 139 case FlexJustifyContent.spaceBetween: |
| 140 leadingSpace = 0.0; |
| 141 betweenSpace = totalChildren > 1 ? remainingSpace / (totalChildren - 1)
: 0.0; |
| 142 break; |
| 143 case FlexJustifyContent.spaceAround: |
| 144 betweenSpace = totalChildren > 0 ? remainingSpace / totalChildren : 0.0; |
| 145 leadingSpace = betweenSpace / 2.0; |
| 146 break; |
| 147 } |
| 148 |
| 149 // Position elements. For now, center the flex items in the cross direction |
| 150 double mainDimPosition = leadingSpace; |
| 151 child = firstChild; |
| 152 while (child != null) { |
| 153 switch (_direction) { |
| 154 case FlexDirection.horizontal: |
| 155 child.parentData.position = new Point(mainDimPosition, size.height / 2
.0 - child.size.height / 2.0); |
| 156 mainDimPosition += child.size.width; |
| 157 break; |
| 158 case FlexDirection.vertical: |
| 159 child.parentData.position = new Point(size.width / 2.0 - child.size.wi
dth / 2.0, mainDimPosition); |
| 160 mainDimPosition += child.size.height; |
| 161 break; |
| 162 } |
| 163 mainDimPosition += betweenSpace; |
| 164 child = child.parentData.nextSibling; |
| 165 } |
111 } | 166 } |
112 | 167 |
113 void hitTestChildren(HitTestResult result, { Point position }) { | 168 void hitTestChildren(HitTestResult result, { Point position }) { |
114 defaultHitTestChildren(result, position: position); | 169 defaultHitTestChildren(result, position: position); |
115 } | 170 } |
116 | 171 |
117 void paint(RenderObjectDisplayList canvas) { | 172 void paint(RenderObjectDisplayList canvas) { |
118 defaultPaint(canvas); | 173 defaultPaint(canvas); |
119 } | 174 } |
120 } | 175 } |
OLD | NEW |