Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(834)

Unified Diff: sky/sdk/lib/rendering/auto_layout.dart

Issue 1230583003: Integrate the linear constraint solver into Sky as a RenderBox subclass. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Address CL concerns Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sky/sdk/lib/rendering/auto_layout.dart
diff --git a/sky/sdk/lib/rendering/auto_layout.dart b/sky/sdk/lib/rendering/auto_layout.dart
new file mode 100644
index 0000000000000000000000000000000000000000..04b952d1b0fc5bd5f748bb0d862cda24d9894078
--- /dev/null
+++ b/sky/sdk/lib/rendering/auto_layout.dart
@@ -0,0 +1,225 @@
+// 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 'box.dart';
+import 'object.dart';
+import 'package:cassowary/cassowary.dart' as al;
+
+/// Hosts the edge parameters and vends useful methods to construct expressions
+/// for constraints. Also sets up and manages implicit constraints and edit
+/// variables. Used as a mixin by layout containers and parent data instances
+/// of render boxes taking part in auto layout
+abstract class _AutoLayoutParamMixin {
+ // Ideally, the edges would all be final, but then they would have to be
+ // initialized before the constructor. Not sure how to do that using a Mixin
Hixie 2015/07/09 00:53:14 Why can't you just use a constructor?
Hixie 2015/07/09 22:05:09 i think you missed this one. :-)
+ al.Param _leftEdge;
+ al.Param _rightEdge;
+ al.Param _topEdge;
+ al.Param _bottomEdge;
+
+ List<al.Constraint> _implicitConstraints;
+
+ al.Param get leftEdge => _leftEdge;
+ al.Param get rightEdge => _rightEdge;
+ al.Param get topEdge => _topEdge;
+ al.Param get bottomEdge => _bottomEdge;
+
+ al.Expression get width => _rightEdge - _leftEdge;
+ al.Expression get height => _bottomEdge - _topEdge;
+
+ al.Expression get horizontalCenter => (_leftEdge + _rightEdge) / al.CM(2.0);
+ al.Expression get verticalCenter => (_topEdge + _bottomEdge) / al.CM(2.0);
+
+ void _setupLayoutParameters(dynamic context) {
+ _leftEdge = new al.Param.withContext(context);
+ _rightEdge = new al.Param.withContext(context);
+ _topEdge = new al.Param.withContext(context);
+ _bottomEdge = new al.Param.withContext(context);
+ }
+
+ void _setupEditVariablesInSolver(al.Solver solver, double priority) {
+ solver.addEditVariables([
+ _leftEdge.variable,
+ _rightEdge.variable,
+ _topEdge.variable,
+ _bottomEdge.variable], priority);
+ }
+
+ void _applyEditsAtSize(al.Solver solver, Size size) {
+ solver.suggestValueForVariable(_leftEdge.variable, 0.0);
+ solver.suggestValueForVariable(_topEdge.variable, 0.0);
+ solver.suggestValueForVariable(_bottomEdge.variable, size.height);
+ solver.suggestValueForVariable(_rightEdge.variable, size.width);
+ }
+
+ void _applyAutolayoutParameterUpdates();
+ List<al.Constraint> _constructImplicitConstraints();
+
+ void _setupImplicitConstraints(al.Solver solver) {
+ List<al.Constraint> implicit = _constructImplicitConstraints();
+
+ if (implicit == null || implicit.length == 0) {
+ return;
+ }
+
+ al.Result result = solver.addConstraints(implicit);
+ assert(result == al.Result.success);
+
+ _implicitConstraints = implicit;
+ }
+
+ void _collectImplicitConstraints(al.Solver solver) {
+ if (_implicitConstraints == null || _implicitConstraints.length == 0) {
+ return;
+ }
+
+ al.Result result = solver.removeConstraints(_implicitConstraints);
+ assert(result == al.Result.success);
+
+ _implicitConstraints = null;
+ }
+}
+
+class AutoLayoutParentData extends BoxParentData
+ with ContainerParentDataMixin<RenderBox>, _AutoLayoutParamMixin {
+
+ final RenderBox _renderBox;
+
+ AutoLayoutParentData(this._renderBox) {
+ _setupLayoutParameters(this);
Hixie 2015/07/09 00:53:15 put constructors before fields
Chinmay 2015/07/09 21:44:19 ack
+ }
+
+ @override
Hixie 2015/07/09 00:53:14 remove the @override annotations (or add them acro
Chinmay 2015/07/09 21:44:20 ack
+ void _applyAutolayoutParameterUpdates() {
Hixie 2015/07/09 00:53:15 Put a comment here explaining that this is called
Chinmay 2015/07/09 21:44:20 ack. Since this is part of the abstract class that
+ BoxConstraints box = new BoxConstraints.tightFor(
+ width: _rightEdge.value - _leftEdge.value,
+ height: _bottomEdge.value - _topEdge.value);
+
+ _renderBox.layout(box, parentUsesSize: false);
+ position = new Point(_leftEdge.value, _topEdge.value);
+ }
+
+ @override
+ List<al.Constraint> _constructImplicitConstraints() {
+ return [
+ // The left edge must be positive
+ _leftEdge >= al.CM(0.0),
+
+ // Width must be positive
+ _rightEdge >= _leftEdge,
+ ];
+ }
+}
Hixie 2015/07/09 00:53:14 you have a blank line after the class open {, so y
Chinmay 2015/07/09 21:44:19 ack
+
+class RenderAutoLayout extends RenderBox
+ with ContainerRenderObjectMixin<RenderBox, AutoLayoutParentData>,
+ RenderBoxContainerDefaultsMixin<RenderBox, AutoLayoutParentData>,
+ _AutoLayoutParamMixin {
+
+ final al.Solver _solver = new al.Solver();
+ List<al.Constraint> _explicitConstraints = new List<al.Constraint>();
+
+ RenderAutoLayout({List<RenderBox> children}) {
Hixie 2015/07/09 00:53:14 put spaces inside { }s around parameter arguments.
Chinmay 2015/07/09 21:44:20 ack
+ _setupLayoutParameters(this);
+ _setupEditVariablesInSolver(_solver, al.Priority.required - 1);
+
Hixie 2015/07/09 00:53:14 remove this blank line; it doesn't help readabilit
Chinmay 2015/07/09 21:44:20 ack
+ addAll(children);
+ }
+
+ /// Adds all the given constraints to the solver. Either all constraints are
+ /// added or none
+ al.Result addConstraints(List<al.Constraint> constraints) {
+ al.Result result = _solver.addConstraints(constraints);
+
+ if (result == al.Result.success) {
+ markNeedsLayout();
+ _explicitConstraints.addAll(constraints);
+ }
+
Hixie 2015/07/09 00:53:14 probably don't need the blank lines here either.
Chinmay 2015/07/09 21:44:20 ack
+ return result;
+ }
+
+ /// Add the given constraint to the solver.
+ al.Result addConstraint(al.Constraint constraint) {
+ al.Result result = _solver.addConstraint(constraint);
+
+ if (result == al.Result.success) {
+ markNeedsLayout();
+ _explicitConstraints.add(constraint);
+ }
+
+ return result;
+ }
+
+ /// Removes all explicitly added constraints.
+ al.Result clearAllConstraints() {
+ al.Result result = _solver.removeConstraints(_explicitConstraints);
+
+ if (result == al.Result.success) {
+ markNeedsLayout();
+ _explicitConstraints = new List<al.Constraint>();
+ }
+
+ return result;
+ }
+
+ @override
+ void setupParentData(RenderObject child) {
+ if (child.parentData is! AutoLayoutParentData) {
+ child.parentData = new AutoLayoutParentData(child);
Hixie 2015/07/09 00:53:14 no { }s around blocks that are only 1 line long
Chinmay 2015/07/09 21:44:20 ack
+ }
+ }
+
+ @override
+ void performLayout() {
+ // Step 1: Update dimensions of self
+ size = constraints.biggest;
Hixie 2015/07/09 00:53:14 If the size isn't configurable, then you should se
Chinmay 2015/07/09 21:44:20 This is something I am not completely sure of TBH.
Hixie 2015/07/09 22:05:09 As far as I can tell, you don't let the size be se
+ _applyEditsAtSize(_solver, size);
+
+ // Step 2: Resolve solver updates and flush parameters
+
+ // We don't iterate over the children, instead, we ask the solver to tell
+ // us the updated parameters. Attached to the parameters (via the context)
+ // are the _AutoLayoutParamMixin instances.
+ for (_AutoLayoutParamMixin update in _solver.flushUpdates()) {
+ update._applyAutolayoutParameterUpdates();
+ }
+ }
+
+ @override
+ void _applyAutolayoutParameterUpdates() {
+ // Nothing to do since the size update has already been presented to the
+ // solver as an edit variable modification. The invokation of this method
+ // only indicates that the value has been flushed to the variable.
+ }
+
+ @override
+ void hitTestChildren(HitTestResult result, {Point position}) =>
Hixie 2015/07/09 00:53:14 Don't use fat arrow if the body isn't on the same
Chinmay 2015/07/09 21:44:20 I have been referring to the expression count (ins
Hixie 2015/07/09 22:05:09 our style guide says => is for single-line declara
+ defaultHitTestChildren(result, position: position);
+
+ @override
+ void paint(PaintingCanvas canvas, Offset offset) =>
+ defaultPaint(canvas, offset);
+
+ @override
+ void adoptChild(RenderObject child) {
+ // Make sure to call super first to setup the parent data
+ super.adoptChild(child);
+ child.parentData._setupImplicitConstraints(_solver);
+ }
+
+ @override
+ void dropChild(RenderObject child) {
+ child.parentData._collectImplicitConstraints(_solver);
+
+ // Call super last as this collects parent data
Hixie 2015/07/09 00:53:14 it doesn't matter, dropChild doesn't touch parentD
Chinmay 2015/07/09 21:44:20 ack
+ super.dropChild(child);
+ }
+
+ @override
+ List<al.Constraint> _constructImplicitConstraints() {
+ // Only edits are present on layout containers
Hixie 2015/07/09 00:53:14 What does this mean?
Chinmay 2015/07/09 21:44:20 ack. Elaborated
+ return null;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698