Merge pull request #1896 from abarth/autolayout2

Add support for autolayout to widgets
diff --git a/examples/layers/rendering/autolayout.dart b/examples/layers/rendering/autolayout.dart
index c2c30c5..f89f4bf 100644
--- a/examples/layers/rendering/autolayout.dart
+++ b/examples/layers/rendering/autolayout.dart
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2016 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.
 
@@ -8,6 +8,45 @@
 import 'package:cassowary/cassowary.dart' as al;
 import 'package:flutter/rendering.dart';
 
+class _MyAutoLayoutDelegate extends AutoLayoutDelegate {
+  AutoLayoutParams p1 = new AutoLayoutParams();
+  AutoLayoutParams p2 = new AutoLayoutParams();
+  AutoLayoutParams p3 = new AutoLayoutParams();
+  AutoLayoutParams p4 = new AutoLayoutParams();
+
+  List<al.Constraint> getConstraints(AutoLayoutParams parentParams) {
+    return <al.Constraint>[
+      // Sum of widths of each box must be equal to that of the container
+      (p1.width + p2.width + p3.width == parentParams.width) as al.Constraint,
+
+      // The boxes must be stacked left to right
+      p1.rightEdge <= p2.leftEdge,
+      p2.rightEdge <= p3.leftEdge,
+
+      // The widths of the first and the third boxes should be equal
+      (p1.width == p3.width) as al.Constraint,
+
+      // The width of the second box should be twice as much as that of the first
+      // and third
+      (p2.width * al.cm(2.0) == p1.width) as al.Constraint,
+
+      // The height of the three boxes should be equal to that of the container
+      (p1.height == p2.height) as al.Constraint,
+      (p2.height == p3.height) as al.Constraint,
+      (p3.height == parentParams.height) as al.Constraint,
+
+      // The fourth box should be half as wide as the second and must be attached
+      // to the right edge of the same (by its center)
+      (p4.width == p2.width / al.cm(2.0)) as al.Constraint,
+      (p4.height == al.cm(50.0)) as al.Constraint,
+      (p4.horizontalCenter == p2.rightEdge) as al.Constraint,
+      (p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
+    ];
+  }
+
+  bool shouldUpdateConstraints(AutoLayoutDelegate oldDelegate) => true;
+}
+
 void main() {
   RenderDecoratedBox c1 = new RenderDecoratedBox(
     decoration: new BoxDecoration(backgroundColor: const Color(0xFFFF0000))
@@ -25,40 +64,22 @@
     decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF))
   );
 
-  RenderAutoLayout root = new RenderAutoLayout(children: <RenderBox>[c1, c2, c3, c4]);
+  _MyAutoLayoutDelegate delegate = new _MyAutoLayoutDelegate();
 
-  AutoLayoutParentData p1 = c1.parentData;
-  AutoLayoutParentData p2 = c2.parentData;
-  AutoLayoutParentData p3 = c3.parentData;
-  AutoLayoutParentData p4 = c4.parentData;
+  RenderAutoLayout root = new RenderAutoLayout(
+    delegate: delegate,
+    children: <RenderBox>[c1, c2, c3, c4]
+  );
 
-  root.addConstraints(<al.Constraint>[
-    // Sum of widths of each box must be equal to that of the container
-    (p1.width + p2.width + p3.width == root.width) as al.Constraint,
+  AutoLayoutParentData parentData1 = c1.parentData;
+  AutoLayoutParentData parentData2 = c2.parentData;
+  AutoLayoutParentData parentData3 = c3.parentData;
+  AutoLayoutParentData parentData4 = c4.parentData;
 
-    // The boxes must be stacked left to right
-    p1.rightEdge <= p2.leftEdge,
-    p2.rightEdge <= p3.leftEdge,
-
-    // The widths of the first and the third boxes should be equal
-    (p1.width == p3.width) as al.Constraint,
-
-    // The width of the second box should be twice as much as that of the first
-    // and third
-    (p2.width * al.cm(2.0) == p1.width) as al.Constraint,
-
-    // The height of the three boxes should be equal to that of the container
-    (p1.height == p2.height) as al.Constraint,
-    (p2.height == p3.height) as al.Constraint,
-    (p3.height == root.height) as al.Constraint,
-
-    // The fourth box should be half as wide as the second and must be attached
-    // to the right edge of the same (by its center)
-    (p4.width == p2.width / al.cm(2.0)) as al.Constraint,
-    (p4.height == al.cm(50.0)) as al.Constraint,
-    (p4.horizontalCenter == p2.rightEdge) as al.Constraint,
-    (p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
-  ]);
+  parentData1.params = delegate.p1;
+  parentData2.params = delegate.p2;
+  parentData3.params = delegate.p3;
+  parentData4.params = delegate.p4;
 
   new RenderingFlutterBinding(root: root);
 }
diff --git a/examples/layers/widgets/autolayout.dart b/examples/layers/widgets/autolayout.dart
new file mode 100644
index 0000000..d7e81f1
--- /dev/null
+++ b/examples/layers/widgets/autolayout.dart
@@ -0,0 +1,87 @@
+// Copyright 2016 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.
+
+// This example shows how to use the Cassowary autolayout system with widgets.
+
+import 'package:cassowary/cassowary.dart' as al;
+import 'package:flutter/widgets.dart';
+
+class _MyAutoLayoutDelegate extends AutoLayoutDelegate {
+  AutoLayoutParams p1 = new AutoLayoutParams();
+  AutoLayoutParams p2 = new AutoLayoutParams();
+  AutoLayoutParams p3 = new AutoLayoutParams();
+  AutoLayoutParams p4 = new AutoLayoutParams();
+
+  List<al.Constraint> getConstraints(AutoLayoutParams parentParams) {
+    return <al.Constraint>[
+      // Sum of widths of each box must be equal to that of the container
+      (p1.width + p2.width + p3.width == parentParams.width) as al.Constraint,
+
+      // The boxes must be stacked left to right
+      p1.rightEdge <= p2.leftEdge,
+      p2.rightEdge <= p3.leftEdge,
+
+      // The widths of the first and the third boxes should be equal
+      (p1.width == p3.width) as al.Constraint,
+
+      // The width of the second box should be twice as much as that of the first
+      // and third
+      (p2.width * al.cm(2.0) == p1.width) as al.Constraint,
+
+      // The height of the three boxes should be equal to that of the container
+      (p1.height == p2.height) as al.Constraint,
+      (p2.height == p3.height) as al.Constraint,
+      (p3.height == parentParams.height) as al.Constraint,
+
+      // The fourth box should be half as wide as the second and must be attached
+      // to the right edge of the same (by its center)
+      (p4.width == p2.width / al.cm(2.0)) as al.Constraint,
+      (p4.height == al.cm(50.0)) as al.Constraint,
+      (p4.horizontalCenter == p2.rightEdge) as al.Constraint,
+      (p4.verticalCenter == p2.height / al.cm(2.0)) as al.Constraint,
+    ];
+  }
+
+  bool shouldUpdateConstraints(AutoLayoutDelegate oldDelegate) => true;
+}
+
+class ColoredBox extends StatelessComponent {
+  ColoredBox({ Key key, this.params, this.color }) : super(key: key);
+
+  final AutoLayoutParams params;
+  final Color color;
+
+  Widget build(BuildContext context) {
+    return new AutoLayoutChild(
+      params: params,
+      child: new DecoratedBox(
+        decoration: new BoxDecoration(backgroundColor: color)
+      )
+    );
+  }
+}
+
+class ColoredBoxes extends StatefulComponent {
+  _ColoredBoxesState createState() => new _ColoredBoxesState();
+}
+
+class _ColoredBoxesState extends State<ColoredBoxes> {
+  final _MyAutoLayoutDelegate delegate = new _MyAutoLayoutDelegate();
+
+  Widget build(BuildContext context) {
+    return new AutoLayout(
+      delegate: delegate,
+      children: <Widget>[
+        new ColoredBox(params: delegate.p1, color: const Color(0xFFFF0000)),
+        new ColoredBox(params: delegate.p2, color: const Color(0xFF00FF00)),
+        new ColoredBox(params: delegate.p3, color: const Color(0xFF0000FF)),
+        new ColoredBox(params: delegate.p4, color: const Color(0xFFFFFFFF)),
+      ]
+    );
+  }
+}
+
+void main() {
+  runApp(new ColoredBoxes());
+}
diff --git a/packages/flutter/lib/src/rendering/auto_layout.dart b/packages/flutter/lib/src/rendering/auto_layout.dart
index 20ec85f..156621d 100644
--- a/packages/flutter/lib/src/rendering/auto_layout.dart
+++ b/packages/flutter/lib/src/rendering/auto_layout.dart
@@ -9,24 +9,23 @@
 
 /// 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 {
-
-  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);
+/// variables.
+class AutoLayoutParams {
+  AutoLayoutParams() {
+    _leftEdge = new al.Param.withContext(this);
+    _rightEdge = new al.Param.withContext(this);
+    _topEdge = new al.Param.withContext(this);
+    _bottomEdge = new al.Param.withContext(this);
   }
 
+  /// The render box with which these parameters are associated.
+  RenderBox _renderBox;
+
   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;
@@ -38,153 +37,154 @@
   al.Expression get horizontalCenter => (_leftEdge + _rightEdge) / al.cm(2.0);
   al.Expression get verticalCenter => (_topEdge + _bottomEdge) / al.cm(2.0);
 
-  void _setupEditVariablesInSolver(al.Solver solver, double priority) {
-    solver.addEditVariables(<al.Variable>[
-        _leftEdge.variable,
-        _rightEdge.variable,
-        _topEdge.variable,
-        _bottomEdge.variable
-      ], priority);
+  List<al.Constraint> _implicitConstraints;
+
+  void _addImplicitConstraints() {
+    assert(_renderBox != null);
+    if (_renderBox.parent == null)
+      return;
+    assert(_renderBox.parent is RenderAutoLayout);
+    final RenderAutoLayout parent = _renderBox.parent;
+    final AutoLayoutParentData parentData = _renderBox.parentData;
+    final List<al.Constraint> implicit = parentData._constructImplicitConstraints();
+    if (implicit == null || implicit.isEmpty)
+      return;
+    final al.Result result = parent._solver.addConstraints(implicit);
+    assert(result == al.Result.success);
+    parent.markNeedsLayout();
+    _implicitConstraints = implicit;
   }
 
-  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 _removeImplicitConstraints() {
+    assert(_renderBox != null);
+    if (_renderBox.parent == null)
+      return;
+    if (_implicitConstraints == null || _implicitConstraints.isEmpty)
+      return;
+    assert(_renderBox.parent is RenderAutoLayout);
+    final RenderAutoLayout parent = _renderBox.parent;
+    final al.Result result = parent._solver.removeConstraints(_implicitConstraints);
+    assert(result == al.Result.success);
+    parent.markNeedsLayout();
+    _implicitConstraints = null;
+  }
+}
+
+class AutoLayoutParentData extends ContainerBoxParentDataMixin<RenderBox> {
+  AutoLayoutParentData(this._renderBox);
+
+  final RenderBox _renderBox;
+
+  AutoLayoutParams get params => _params;
+  AutoLayoutParams _params;
+  void set params(AutoLayoutParams value) {
+    if (_params == value)
+      return;
+    if (_params != null) {
+      _params._removeImplicitConstraints();
+      _params._renderBox = null;
+    }
+    _params = value;
+    if (_params != null) {
+      assert(_params._renderBox == null);
+      _params._renderBox = _renderBox;
+      _params._addImplicitConstraints();
+    }
   }
 
-  /// Applies the parameter updates.
-  ///
-  /// This method is called when the solver has updated at least one of the
-  /// layout parameters of this object. The object is now responsible for
-  /// applying this update to its other properties (if necessary).
-  void _applyAutolayoutParameterUpdates();
+  BoxConstraints get _constraints {
+    return new BoxConstraints.tightFor(
+      width: _params._rightEdge.value - _params._leftEdge.value,
+      height: _params._bottomEdge.value - _params._topEdge.value
+    );
+  }
 
   /// Returns the set of implicit constraints that need to be applied to all
   /// instances of this class when they are moved into a render object with an
   /// active solver. If no implicit constraints needs to be applied, the object
   /// may return null.
-  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 _removeImplicitConstraints(al.Solver solver) {
-    if (_implicitConstraints == null || _implicitConstraints.length == 0) {
-      return;
-    }
-
-    al.Result result = solver.removeConstraints(_implicitConstraints);
-    assert(result == al.Result.success);
-
-    _implicitConstraints = null;
+  List<al.Constraint> _constructImplicitConstraints() {
+    return <al.Constraint>[
+      _params._leftEdge >= al.cm(0.0), // The left edge must be positive.
+      _params._rightEdge >= _params._leftEdge, // Width must be positive.
+    ];
   }
 }
 
-class AutoLayoutParentData extends ContainerBoxParentDataMixin<RenderBox> with _AutoLayoutParamMixin {
+abstract class AutoLayoutDelegate {
+  const AutoLayoutDelegate();
 
-  AutoLayoutParentData(this._renderBox) {
-    _setupLayoutParameters(this);
-  }
-
-  final RenderBox _renderBox;
-
-  void _applyAutolayoutParameterUpdates() {
-    // This is called by the parent's layout function
-    // to lay our box out.
-    assert(_renderBox.parentData == this);
-    assert(() {
-      final RenderAutoLayout parent = _renderBox.parent;
-      assert(parent.debugDoingThisLayout);
-    });
-    BoxConstraints size = new BoxConstraints.tightFor(
-      width: _rightEdge.value - _leftEdge.value,
-      height: _bottomEdge.value - _topEdge.value
-    );
-    _renderBox.layout(size);
-    offset = new Offset(_leftEdge.value, _topEdge.value);
-  }
-
-  List<al.Constraint> _constructImplicitConstraints() {
-    return <al.Constraint>[
-      _leftEdge >= al.cm(0.0), // The left edge must be positive.
-      _rightEdge >= _leftEdge, // Width must be positive.
-    ];
-  }
-
+  List<al.Constraint> getConstraints(AutoLayoutParams parentParams);
+  bool shouldUpdateConstraints(AutoLayoutDelegate oldDelegate);
 }
 
 class RenderAutoLayout extends RenderBox
     with ContainerRenderObjectMixin<RenderBox, AutoLayoutParentData>,
-         RenderBoxContainerDefaultsMixin<RenderBox, AutoLayoutParentData>,
-         _AutoLayoutParamMixin {
+         RenderBoxContainerDefaultsMixin<RenderBox, AutoLayoutParentData> {
 
-  RenderAutoLayout({ List<RenderBox> children }) {
-    _setupLayoutParameters(this);
-    _setupEditVariablesInSolver(_solver, al.Priority.required - 1);
+  RenderAutoLayout({
+    AutoLayoutDelegate delegate,
+    List<RenderBox> children
+  }) : _delegate = delegate, _needToUpdateConstraints = (delegate != null) {
+    _solver.addEditVariables(<al.Variable>[
+        _params._leftEdge.variable,
+        _params._rightEdge.variable,
+        _params._topEdge.variable,
+        _params._bottomEdge.variable
+      ], al.Priority.required - 1);
+
     addAll(children);
   }
 
+  AutoLayoutDelegate get delegate => _delegate;
+  AutoLayoutDelegate _delegate;
+  void set delegate(AutoLayoutDelegate newDelegate) {
+    if (_delegate == newDelegate)
+      return;
+    AutoLayoutDelegate oldDelegate = _delegate;
+    _delegate = newDelegate;
+    if (newDelegate == null) {
+      assert(oldDelegate != null);
+      _needToUpdateConstraints = true;
+      markNeedsLayout();
+    } else if (oldDelegate == null ||
+        newDelegate.runtimeType != oldDelegate.runtimeType ||
+        newDelegate.shouldUpdateConstraints(oldDelegate)) {
+      _needToUpdateConstraints = true;
+      markNeedsLayout();
+    }
+  }
+
+  bool _needToUpdateConstraints;
+
+  final AutoLayoutParams _params = new AutoLayoutParams();
+
   final al.Solver _solver = new al.Solver();
-  List<al.Constraint> _explicitConstraints = new List<al.Constraint>();
+  final List<al.Constraint> _explicitConstraints = new List<al.Constraint>();
 
-  /// 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();
+  void _addExplicitConstraints(List<al.Constraint> constraints) {
+    if (constraints == null || constraints.isEmpty)
+      return;
+    if (_solver.addConstraints(constraints) == al.Result.success)
       _explicitConstraints.addAll(constraints);
-    }
-    return result;
   }
 
-  /// Adds 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;
+  void _clearExplicitConstraints() {
+    if (_solver.removeConstraints(_explicitConstraints) == al.Result.success)
+      _explicitConstraints.clear();
   }
 
   void adoptChild(RenderObject child) {
     // Make sure to call super first to setup the parent data
     super.adoptChild(child);
     final AutoLayoutParentData childParentData = child.parentData;
-    childParentData._setupImplicitConstraints(_solver);
+    childParentData._params?._addImplicitConstraints();
     assert(child.parentData == childParentData);
   }
 
   void dropChild(RenderObject child) {
     final AutoLayoutParentData childParentData = child.parentData;
-    childParentData._removeImplicitConstraints(_solver);
+    childParentData._params?._removeImplicitConstraints();
     assert(child.parentData == childParentData);
     super.dropChild(child);
   }
@@ -201,23 +201,41 @@
   }
 
   void performLayout() {
-    // Step 1: Update dimensions of self
-    _applyEditsAtSize(_solver, size);
+    // Step 1: Update constraints if needed.
+    if (_needToUpdateConstraints) {
+      _clearExplicitConstraints();
+      if (_delegate != null)
+        _addExplicitConstraints(_delegate.getConstraints(_params));
+      _needToUpdateConstraints = false;
+    }
 
-    // Step 2: Resolve solver updates and flush parameters
+    // Step 2: Update dimensions of this render object.
+    _solver
+      ..suggestValueForVariable(_params._leftEdge.variable, 0.0)
+      ..suggestValueForVariable(_params._topEdge.variable, 0.0)
+      ..suggestValueForVariable(_params._bottomEdge.variable, size.height)
+      ..suggestValueForVariable(_params._rightEdge.variable, size.width);
+
+    // Step 3: 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();
+    // are the AutoLayoutParams instances.
+    for (AutoLayoutParams update in _solver.flushUpdates()) {
+      RenderBox child = update._renderBox;
+      if (child != null)
+        _layoutChild(child);
     }
   }
 
-  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.
+  void _layoutChild(RenderBox child) {
+    assert(debugDoingThisLayout);
+    assert(child.parent == this);
+    final AutoLayoutParentData childParentData = child.parentData;
+    child.layout(childParentData._constraints);
+    childParentData.offset = new Offset(childParentData._params._leftEdge.value,
+                                        childParentData._params._topEdge.value);
+    assert(child.parentData == childParentData);
   }
 
   bool hitTestChildren(HitTestResult result, { Point position }) {
@@ -227,11 +245,4 @@
   void paint(PaintingContext context, Offset offset) {
     defaultPaint(context, offset);
   }
-
-  List<al.Constraint> _constructImplicitConstraints() {
-    // Only edits variables are present on layout containers. If, in the future,
-    // implicit constraints (for say margins, padding, etc.) need to be added,
-    // they must be returned from here.
-    return null;
-  }
 }
diff --git a/packages/flutter/lib/src/widgets/auto_layout.dart b/packages/flutter/lib/src/widgets/auto_layout.dart
new file mode 100644
index 0000000..b915d10
--- /dev/null
+++ b/packages/flutter/lib/src/widgets/auto_layout.dart
@@ -0,0 +1,42 @@
+// 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 'package:flutter/rendering.dart';
+
+import 'framework.dart';
+
+export 'package:flutter/rendering.dart' show
+    AutoLayoutParams,
+    AutoLayoutDelegate;
+
+class AutoLayout extends MultiChildRenderObjectWidget {
+  AutoLayout({
+    Key key,
+    this.delegate,
+    List<Widget> children: const <Widget>[]
+  }) : super(key: key, children: children);
+
+  final AutoLayoutDelegate delegate;
+
+  RenderAutoLayout createRenderObject() => new RenderAutoLayout(delegate: delegate);
+
+  void updateRenderObject(RenderAutoLayout renderObject, AutoLayout oldWidget) {
+    renderObject.delegate = delegate;
+  }
+}
+
+class AutoLayoutChild extends ParentDataWidget<AutoLayout> {
+  AutoLayoutChild({ Key key, this.params, Widget child })
+    : super(key: key, child: child);
+
+  final AutoLayoutParams params;
+
+  void applyParentData(RenderObject renderObject) {
+    assert(renderObject.parentData is AutoLayoutParentData);
+    final AutoLayoutParentData parentData = renderObject.parentData;
+    // AutoLayoutParentData filters out redundant writes and marks needs layout
+    // as appropriate.
+    parentData.params = params;
+  }
+}
diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart
index 0f565b5..e764483 100644
--- a/packages/flutter/lib/widgets.dart
+++ b/packages/flutter/lib/widgets.dart
@@ -6,6 +6,7 @@
 library widgets;
 
 export 'src/widgets/asset_vendor.dart';
+export 'src/widgets/auto_layout.dart';
 export 'src/widgets/basic.dart';
 export 'src/widgets/binding.dart';
 export 'src/widgets/checked_mode_banner.dart';