Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 import 'box.dart'; | |
| 6 import 'object.dart'; | |
| 7 import 'package:cassowary/cassowary.dart' as AL; | |
|
abarth-chromium
2015/07/08 22:22:02
ditto
Chinmay
2015/07/08 23:01:01
ack
| |
| 8 | |
| 9 class AutoLayoutParentData extends BoxParentData | |
| 10 with ContainerParentDataMixin<RenderBox>, _AutoLayoutParamMixin { | |
| 11 | |
| 12 final RenderBox _renderBox; | |
| 13 | |
| 14 AutoLayoutParentData(this._renderBox) { | |
| 15 _setupLayoutParameters(this); | |
| 16 } | |
| 17 | |
| 18 @override | |
| 19 void _applyAutolayoutParameterUpdates() { | |
| 20 BoxConstraints box = new BoxConstraints.tightFor( | |
| 21 width: _rightEdge.value - _leftEdge.value, | |
| 22 height: _bottomEdge.value - _topEdge.value); | |
| 23 | |
| 24 _renderBox.layout(box, parentUsesSize: false); | |
| 25 this.position = new Point(_leftEdge.value, _topEdge.value); | |
|
abarth-chromium
2015/07/08 22:22:01
No need for |this.|
Chinmay
2015/07/08 23:01:01
ack
| |
| 26 } | |
| 27 | |
| 28 @override | |
| 29 List<AL.Constraint> _constructImplicitConstraints() { | |
| 30 return [ | |
| 31 // The left edge must be positive | |
| 32 _leftEdge >= AL.CM(0.0), | |
| 33 | |
| 34 // Width must be positive | |
| 35 _rightEdge >= _leftEdge, | |
| 36 ]; | |
| 37 } | |
| 38 } | |
| 39 | |
| 40 class RenderAutoLayout extends RenderBox | |
| 41 with ContainerRenderObjectMixin<RenderBox, AutoLayoutParentData>, | |
| 42 RenderBoxContainerDefaultsMixin<RenderBox, AutoLayoutParentData>, | |
| 43 _AutoLayoutParamMixin { | |
| 44 | |
| 45 final AL.Solver _solver = new AL.Solver(); | |
| 46 List<AL.Constraint> _explicitConstraints = new List<AL.Constraint>(); | |
| 47 | |
| 48 RenderAutoLayout({List<RenderBox> children}) { | |
| 49 _setupLayoutParameters(this); | |
| 50 _setupEditVariablesInSolver(_solver, AL.Priority.required - 1); | |
| 51 | |
| 52 addAll(children); | |
| 53 } | |
| 54 | |
| 55 /// Adds all the given constraints to the solver. Either all constraints are | |
| 56 /// added or none | |
| 57 AL.Result addConstraints(List<AL.Constraint> constraints) { | |
| 58 AL.Result res = _solver.addConstraints(constraints); | |
|
abarth-chromium
2015/07/08 22:22:01
s/res/result/
Please use complete words in variab
Chinmay
2015/07/08 23:01:01
ack
| |
| 59 | |
| 60 if (res == AL.Result.success) { | |
| 61 markNeedsLayout(); | |
| 62 _explicitConstraints.addAll(constraints); | |
| 63 } | |
| 64 | |
| 65 return res; | |
| 66 } | |
| 67 | |
| 68 /// Add the given constraint to the solver. | |
| 69 AL.Result addConstraint(AL.Constraint constraint) { | |
| 70 AL.Result res = _solver.addConstraint(constraint); | |
| 71 | |
| 72 if (res == AL.Result.success) { | |
| 73 markNeedsLayout(); | |
| 74 _explicitConstraints.add(constraint); | |
| 75 } | |
| 76 | |
| 77 return res; | |
| 78 } | |
| 79 | |
| 80 /// Removes all explicitly added constraints. | |
| 81 AL.Result clearAllConstraints() { | |
| 82 AL.Result res = _solver.removeConstraints(_explicitConstraints); | |
| 83 | |
| 84 if (res == AL.Result.success) { | |
| 85 markNeedsLayout(); | |
| 86 _explicitConstraints = new List<AL.Constraint>(); | |
| 87 } | |
| 88 | |
| 89 return res; | |
| 90 } | |
| 91 | |
| 92 @override | |
| 93 void setupParentData(RenderObject child) { | |
| 94 if (child.parentData is! AutoLayoutParentData) { | |
| 95 child.parentData = new AutoLayoutParentData(child); | |
| 96 } | |
| 97 } | |
| 98 | |
| 99 @override | |
| 100 void set size(Size value) { | |
| 101 super.size = value; | |
| 102 _applyEditsAtSize(_solver, value); | |
| 103 } | |
|
abarth-chromium
2015/07/08 22:22:02
You shouldn't need to override the size setter. T
Chinmay
2015/07/08 23:01:01
ack. Good to know.
| |
| 104 | |
| 105 @override | |
| 106 void performLayout() { | |
| 107 // Step 1: Update dimensions of self | |
| 108 size = constraints.smallest; | |
|
abarth-chromium
2015/07/08 22:22:01
Typically we default to constraints.biggest becaus
Chinmay
2015/07/08 23:01:01
ack
| |
| 109 | |
| 110 // Step 2: Resolve solver updates and flush parameters | |
| 111 | |
| 112 // We don't iterate over the children, instead, we ask the solver to tell | |
| 113 // us the updated parameters. Attached to the parameters (via the context) | |
| 114 // are the _AutoLayoutParamMixin instances. | |
| 115 for (_AutoLayoutParamMixin update in _solver.flushUpdates()) { | |
| 116 update._applyAutolayoutParameterUpdates(); | |
| 117 } | |
| 118 } | |
| 119 | |
| 120 @override | |
| 121 void _applyAutolayoutParameterUpdates() { | |
| 122 // Nothing to do since the size update has already been presented to the | |
| 123 // solver as an edit variable modification. The invokation of this method | |
| 124 // only indicates that the value has been flushed to the variable. | |
| 125 } | |
| 126 | |
| 127 @override | |
| 128 void hitTestChildren(HitTestResult result, {Point position}) => | |
| 129 defaultHitTestChildren(result, position: position); | |
| 130 | |
| 131 @override | |
| 132 void paint(PaintingCanvas canvas, Offset offset) => | |
| 133 defaultPaint(canvas, offset); | |
| 134 | |
| 135 @override | |
| 136 void adoptChild(RenderObject child) { | |
| 137 // Make sure to call super first to setup the parent data | |
| 138 super.adoptChild(child); | |
| 139 child.parentData._setupImplicitConstraints(_solver); | |
| 140 } | |
| 141 | |
| 142 @override | |
| 143 void dropChild(RenderObject child) { | |
| 144 child.parentData._collectImplicitConstraints(_solver); | |
| 145 | |
| 146 // Call super last as this collects parent data | |
| 147 super.dropChild(child); | |
| 148 } | |
| 149 | |
| 150 @override | |
| 151 List<AL.Constraint> _constructImplicitConstraints() { | |
| 152 // Only edits are present on layout containers | |
| 153 return null; | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 abstract class _AutoLayoutParamMixin { | |
|
abarth-chromium
2015/07/08 22:22:01
I would move this up in the file given that it's r
Chinmay
2015/07/08 23:01:01
ack. I was trying to keep the internal classes tow
| |
| 158 // Ideally, the edges would all be final, but then they would have to be | |
| 159 // initialized before the constructor. Not sure how to do that using a Mixin | |
| 160 AL.Param _leftEdge; | |
| 161 AL.Param _rightEdge; | |
| 162 AL.Param _topEdge; | |
| 163 AL.Param _bottomEdge; | |
| 164 | |
| 165 List<AL.Constraint> _implicitConstraints; | |
| 166 | |
| 167 AL.Param get leftEdge => _leftEdge; | |
| 168 AL.Param get rightEdge => _rightEdge; | |
| 169 AL.Param get topEdge => _topEdge; | |
| 170 AL.Param get bottomEdge => _bottomEdge; | |
| 171 | |
| 172 AL.Expression get width => _rightEdge - _leftEdge; | |
| 173 AL.Expression get height => _bottomEdge - _topEdge; | |
| 174 | |
| 175 AL.Expression get horizontalCenter => (_leftEdge + _rightEdge) / AL.CM(2.0); | |
| 176 AL.Expression get verticalCenter => (_topEdge + _bottomEdge) / AL.CM(2.0); | |
| 177 | |
| 178 void _setupLayoutParameters(dynamic context) { | |
| 179 _leftEdge = new AL.Param.withContext(context); | |
| 180 _rightEdge = new AL.Param.withContext(context); | |
| 181 _topEdge = new AL.Param.withContext(context); | |
| 182 _bottomEdge = new AL.Param.withContext(context); | |
| 183 } | |
| 184 | |
| 185 void _setupEditVariablesInSolver(AL.Solver solver, double priority) { | |
| 186 solver.addEditVariables([ | |
| 187 _leftEdge.variable, | |
| 188 _rightEdge.variable, | |
| 189 _topEdge.variable, | |
| 190 _bottomEdge.variable], priority); | |
| 191 } | |
| 192 | |
| 193 void _applyEditsAtSize(AL.Solver solver, Size size) { | |
| 194 solver.suggestValueForVariable(_leftEdge.variable, 0.0); | |
| 195 solver.suggestValueForVariable(_topEdge.variable, 0.0); | |
| 196 solver.suggestValueForVariable(_bottomEdge.variable, size.height); | |
| 197 solver.suggestValueForVariable(_rightEdge.variable, size.width); | |
| 198 } | |
| 199 | |
| 200 void _applyAutolayoutParameterUpdates(); | |
| 201 List<AL.Constraint> _constructImplicitConstraints(); | |
| 202 | |
| 203 void _setupImplicitConstraints(AL.Solver solver) { | |
| 204 List<AL.Constraint> implicit = _constructImplicitConstraints(); | |
| 205 | |
| 206 if (implicit == null || implicit.length == 0) { | |
| 207 return; | |
| 208 } | |
| 209 | |
| 210 AL.Result res = solver.addConstraints(implicit); | |
| 211 assert(res == AL.Result.success); | |
| 212 | |
| 213 _implicitConstraints = implicit; | |
| 214 } | |
| 215 | |
| 216 void _collectImplicitConstraints(AL.Solver solver) { | |
| 217 if (_implicitConstraints == null || _implicitConstraints.length == 0) { | |
| 218 return; | |
| 219 } | |
| 220 | |
| 221 AL.Result res = solver.removeConstraints(_implicitConstraints); | |
| 222 assert(res == AL.Result.success); | |
| 223 | |
| 224 _implicitConstraints = null; | |
| 225 } | |
| 226 } | |
| OLD | NEW |