diff --git a/examples/widgets/sector.dart b/examples/widgets/sector.dart index 85f6c2eb25c..c8a01dbae7c 100644 --- a/examples/widgets/sector.dart +++ b/examples/widgets/sector.dart @@ -72,7 +72,7 @@ class SectorApp extends App { child: new Row([ new RaisedButton( enabled: enabledAdd, - child: new ShrinkWrapWidth( + child: new IntrinsicWidth( child: new Row([ new Container( padding: new EdgeDims.all(4.0), @@ -86,7 +86,7 @@ class SectorApp extends App { ), new RaisedButton( enabled: enabledRemove, - child: new ShrinkWrapWidth( + child: new IntrinsicWidth( child: new Row([ new Container( padding: new EdgeDims.all(4.0), diff --git a/sky/packages/sky/lib/src/rendering/error.dart b/sky/packages/sky/lib/src/rendering/error.dart index 80124d8022d..7bd1abe9885 100644 --- a/sky/packages/sky/lib/src/rendering/error.dart +++ b/sky/packages/sky/lib/src/rendering/error.dart @@ -9,6 +9,7 @@ import 'package:sky/src/rendering/object.dart'; const double _kMaxWidth = 100000.0; const double _kMaxHeight = 100000.0; +/// A render object used as a placeholder when an error occurs class RenderErrorBox extends RenderBox { double getMinIntrinsicWidth(BoxConstraints constraints) { diff --git a/sky/packages/sky/lib/src/rendering/grid.dart b/sky/packages/sky/lib/src/rendering/grid.dart index 2361f3be873..f08377a0677 100644 --- a/sky/packages/sky/lib/src/rendering/grid.dart +++ b/sky/packages/sky/lib/src/rendering/grid.dart @@ -5,12 +5,10 @@ import 'package:sky/src/rendering/box.dart'; import 'package:sky/src/rendering/object.dart'; -class GridParentData extends BoxParentData with ContainerParentDataMixin {} - -class GridMetrics { +class _GridMetrics { // Grid is width-in, height-out. We fill the max width and adjust height // accordingly. - factory GridMetrics({ double width, int childCount, double maxChildExtent }) { + factory _GridMetrics({ double width, int childCount, double maxChildExtent }) { assert(width != null); assert(childCount != null); assert(maxChildExtent != null); @@ -31,10 +29,10 @@ class GridMetrics { double height = childPadding * (rowCount + 1) + (childExtent * rowCount); Size childSize = new Size(childExtent, childExtent); Size size = new Size(width, height); - return new GridMetrics._(size, childSize, childrenPerRow, childPadding, rowCount); + return new _GridMetrics._(size, childSize, childrenPerRow, childPadding, rowCount); } - const GridMetrics._(this.size, this.childSize, this.childrenPerRow, this.childPadding, this.rowCount); + const _GridMetrics._(this.size, this.childSize, this.childrenPerRow, this.childPadding, this.rowCount); final Size size; final Size childSize; @@ -43,6 +41,15 @@ class GridMetrics { final int rowCount; } +/// Parent data for use with [RenderGrid] +class GridParentData extends BoxParentData with ContainerParentDataMixin {} + +/// Implements the grid layout algorithm +/// +/// In grid layout, children are arranged into rows and collumns in on a two +/// dimensional grid. The grid determines how many children will be placed in +/// each row by making the children as wide as possible while still respecting +/// the given [maxChildExtent]. class RenderGrid extends RenderBox with ContainerRenderObjectMixin, RenderBoxContainerDefaultsMixin { RenderGrid({ Iterable children, double maxChildExtent }) { @@ -66,32 +73,21 @@ class RenderGrid extends RenderBox with ContainerRenderObjectMixin { - // ProxyBox assumes the child will be at 0,0 and will have the same size - RenderProxyBox([RenderBox child = null]) { this.child = child; } @@ -72,6 +81,15 @@ class RenderProxyBox extends RenderBox with RenderObjectWithChildMixin _additionalConstraints; + BoxConstraints _additionalConstraints; void set additionalConstraints (BoxConstraints newConstraints) { assert(newConstraints != null); if (_additionalConstraints == newConstraints) @@ -126,6 +145,14 @@ class RenderConstrainedBox extends RenderProxyBox { String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}additionalConstraints: ${additionalConstraints}\n'; } +/// Forces child to layout at a specific aspect ratio +/// +/// The width of this render object is the largest width permited by the layout +/// constraints. The height of the render object is determined by applying the +/// given aspect ratio to the width. +/// +/// The aspect ratio is expressed as a ratio of width to height. For example, +/// a 16:9 width:height aspect ratio would have a value of 16.0/9.0. class RenderAspectRatio extends RenderProxyBox { RenderAspectRatio({ RenderBox child, @@ -134,8 +161,12 @@ class RenderAspectRatio extends RenderProxyBox { assert(_aspectRatio != null); } - double _aspectRatio; + /// The aspect ratio to use when computing the height from the width + /// + /// The aspect ratio is expressed as a ratio of width to height. For example, + /// a 16:9 width:height aspect ratio would have a value of 16.0/9.0. double get aspectRatio => _aspectRatio; + double _aspectRatio; void set aspectRatio (double newAspectRatio) { assert(newAspectRatio != null); if (_aspectRatio == newAspectRatio) @@ -172,24 +203,29 @@ class RenderAspectRatio extends RenderProxyBox { String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}aspectRatio: ${aspectRatio}\n'; } -class RenderShrinkWrapWidth extends RenderProxyBox { +/// Sizes its child to the child's intrinsic width +/// +/// This class will size its child's width to the child's maximum intrinsic +/// width. If [stepWidth] is non-null, the child's width will be snapped to a +/// multiple of the [stepWidth]. Similarly, if [stepHeight] is non-null, the +/// child's height will be snapped to a multiple of the [stepHeight]. +/// +/// This class is useful, for example, when unlimited width is available and +/// you would like a child that would otherwise attempt to expand infinitely to +/// instead size itself to a more reasonable width. +/// +/// Note: This class is relatively expensive. Avoid using it where possible. +class RenderIntrinsicWidth extends RenderProxyBox { - // This class will attempt to size its child to the child's maximum - // intrinsic width, snapped to a multiple of the stepWidth, if one - // is provided, and given the provided constraints; and will then - // adopt the child's resulting dimensions. - - // Note: laying out this class is relatively expensive. Avoid using - // it where possible. - - RenderShrinkWrapWidth({ + RenderIntrinsicWidth({ double stepWidth, double stepHeight, RenderBox child }) : _stepWidth = stepWidth, _stepHeight = stepHeight, super(child); - double _stepWidth; + /// If non-null, force the child's width to be a multiple of this value double get stepWidth => _stepWidth; + double _stepWidth; void set stepWidth(double newStepWidth) { if (newStepWidth == _stepWidth) return; @@ -197,8 +233,9 @@ class RenderShrinkWrapWidth extends RenderProxyBox { markNeedsLayout(); } - double _stepHeight; + /// If non-null, force the child's height to be a multiple of this value double get stepHeight => _stepHeight; + double _stepHeight; void set stepHeight(double newStepHeight) { if (newStepHeight == _stepHeight) return; @@ -206,7 +243,7 @@ class RenderShrinkWrapWidth extends RenderProxyBox { markNeedsLayout(); } - static double applyStep(double input, double step) { + static double _applyStep(double input, double step) { if (step == null) return input; return (input / step).ceil() * step; @@ -218,7 +255,7 @@ class RenderShrinkWrapWidth extends RenderProxyBox { return constraints; double width = child.getMaxIntrinsicWidth(constraints); assert(width == constraints.constrainWidth(width)); - return constraints.tightenWidth(applyStep(width, _stepWidth)); + return constraints.tightenWidth(_applyStep(width, _stepWidth)); } double getMinIntrinsicWidth(BoxConstraints constraints) { @@ -229,21 +266,21 @@ class RenderShrinkWrapWidth extends RenderProxyBox { if (child == null) return constraints.constrainWidth(0.0); double childResult = child.getMaxIntrinsicWidth(constraints); - return constraints.constrainWidth(applyStep(childResult, _stepWidth)); + return constraints.constrainWidth(_applyStep(childResult, _stepWidth)); } double getMinIntrinsicHeight(BoxConstraints constraints) { if (child == null) return constraints.constrainHeight(0.0); double childResult = child.getMinIntrinsicHeight(_getInnerConstraints(constraints)); - return constraints.constrainHeight(applyStep(childResult, _stepHeight)); + return constraints.constrainHeight(_applyStep(childResult, _stepHeight)); } double getMaxIntrinsicHeight(BoxConstraints constraints) { if (child == null) return constraints.constrainHeight(0.0); double childResult = child.getMaxIntrinsicHeight(_getInnerConstraints(constraints)); - return constraints.constrainHeight(applyStep(childResult, _stepHeight)); + return constraints.constrainHeight(_applyStep(childResult, _stepHeight)); } void performLayout() { @@ -262,16 +299,19 @@ class RenderShrinkWrapWidth extends RenderProxyBox { } -class RenderShrinkWrapHeight extends RenderProxyBox { +/// Sizes its child to the child's intrinsic height +/// +/// This class will size its child's height to the child's maximum intrinsic +/// height. +/// +/// This class is useful, for example, when unlimited height is available and +/// you would like a child that would otherwise attempt to expand infinitely to +/// instead size itself to a more reasonable height. +/// +/// Note: This class is relatively expensive. Avoid using it where possible. +class RenderIntrinsicHeight extends RenderProxyBox { - // This class will attempt to size its child to the child's maximum - // intrinsic height, given the provided constraints; and will then - // adopt the child's resulting dimensions. - - // Note: laying out this class is relatively expensive. Avoid using - // it where possible. - - RenderShrinkWrapHeight({ + RenderIntrinsicHeight({ RenderBox child }) : super(child); @@ -317,14 +357,25 @@ class RenderShrinkWrapHeight extends RenderProxyBox { } +/// Makes its child partially transparent +/// +/// This class paints its child into an intermediate buffer and then blends the +/// child back into the scene partially transparent. +/// +/// Note: This class is relatively expensive because it requires painting the +/// child into an intermediate buffer. class RenderOpacity extends RenderProxyBox { RenderOpacity({ RenderBox child, double opacity }) : this._opacity = opacity, super(child) { assert(opacity >= 0.0 && opacity <= 1.0); } - double _opacity; + /// The fraction to scale the child's alpha value + /// + /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent + /// (i.e., invisible). double get opacity => _opacity; + double _opacity; void set opacity (double newOpacity) { assert(newOpacity != null); assert(newOpacity >= 0.0 && newOpacity <= 1.0); @@ -349,13 +400,21 @@ class RenderOpacity extends RenderProxyBox { } } +/// Applies a color filter when painting its child +/// +/// This class paints its child into an intermediate buffer and then blends the +/// child back into the scene using a color filter. +/// +/// Note: This class is relatively expensive because it requires painting the +/// child into an intermediate buffer. class RenderColorFilter extends RenderProxyBox { RenderColorFilter({ RenderBox child, Color color, sky.TransferMode transferMode }) : _color = color, _transferMode = transferMode, super(child) { } - Color _color; + /// The color to use as input to the color filter Color get color => _color; + Color _color; void set color (Color newColor) { assert(newColor != null); if (_color == newColor) @@ -364,8 +423,9 @@ class RenderColorFilter extends RenderProxyBox { markNeedsPaint(); } - sky.TransferMode _transferMode; + /// The transfer mode to use when combining the child's painting and the [color] sky.TransferMode get transferMode => _transferMode; + sky.TransferMode _transferMode; void set transferMode (sky.TransferMode newTransferMode) { assert(newTransferMode != null); if (_transferMode == newTransferMode) @@ -380,6 +440,9 @@ class RenderColorFilter extends RenderProxyBox { } } +/// Clips its child using a rectangle +/// +/// Prevents its child from painting outside its bounds. class RenderClipRect extends RenderProxyBox { RenderClipRect({ RenderBox child }) : super(child); @@ -389,6 +452,11 @@ class RenderClipRect extends RenderProxyBox { } } +/// Clips its child using a rounded rectangle +/// +/// Creates a rounded rectangle from its layout dimensions and the given x and +/// y radius values and prevents its child from painting outside that rounded +/// rectangle. class RenderClipRRect extends RenderProxyBox { RenderClipRRect({ RenderBox child, double xRadius, double yRadius }) : _xRadius = xRadius, _yRadius = yRadius, super(child) { @@ -396,8 +464,12 @@ class RenderClipRRect extends RenderProxyBox { assert(_yRadius != null); } - double _xRadius; + /// The radius of the rounded corners in the horizontal direction + /// + /// Values are clamped to be between zero and half the width of the render + /// object. double get xRadius => _xRadius; + double _xRadius; void set xRadius (double newXRadius) { assert(newXRadius != null); if (_xRadius == newXRadius) @@ -406,8 +478,12 @@ class RenderClipRRect extends RenderProxyBox { markNeedsPaint(); } - double _yRadius; + /// The radius of the rounded corners in the vertical direction + /// + /// Values are clamped to be between zero and half the height of the render + /// object. double get yRadius => _yRadius; + double _yRadius; void set yRadius (double newYRadius) { assert(newYRadius != null); if (_yRadius == newYRadius) @@ -425,6 +501,10 @@ class RenderClipRRect extends RenderProxyBox { } } +/// Clips its child using an oval +/// +/// Inscribes an oval into its layout dimensions and prevents its child from +/// painting outside that oval. class RenderClipOval extends RenderProxyBox { RenderClipOval({ RenderBox child }) : super(child); @@ -447,22 +527,40 @@ class RenderClipOval extends RenderProxyBox { } } +/// Where to paint a box decoration enum BoxDecorationPosition { + /// Paint the box decoration behind the children background, + + /// Paint the box decoration in front of the children foreground, } +/// Paints a [BoxDecoration] either before or after its child paints class RenderDecoratedBox extends RenderProxyBox { RenderDecoratedBox({ BoxDecoration decoration, RenderBox child, - this.position: BoxDecorationPosition.background - }) : _painter = new BoxPainter(decoration), super(child); + BoxDecorationPosition position: BoxDecorationPosition.background + }) : _painter = new BoxPainter(decoration), + _position = position, + super(child) { + assert(decoration != null); + assert(position != null); + } - BoxDecorationPosition position; - final BoxPainter _painter; + /// Where to paint the box decoration + BoxDecorationPosition get position => _position; + BoxDecorationPosition _position; + void set position (BoxDecorationPosition newPosition) { + assert(newPosition != null); + if (newPosition == _position) + return; + markNeedsPaint(); + } + /// What decoration to paint BoxDecoration get decoration => _painter.decoration; void set decoration (BoxDecoration newDecoration) { assert(newDecoration != null); @@ -474,6 +572,8 @@ class RenderDecoratedBox extends RenderProxyBox { markNeedsPaint(); } + final BoxPainter _painter; + bool get _needsBackgroundImageListener { return attached && _painter.decoration != null && @@ -513,6 +613,7 @@ class RenderDecoratedBox extends RenderProxyBox { String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}decoration:\n${_painter.decoration.toString(prefix + " ")}\n'; } +/// Applies a transformation before painting its child class RenderTransform extends RenderProxyBox { RenderTransform({ Matrix4 transform, @@ -524,10 +625,13 @@ class RenderTransform extends RenderProxyBox { this.origin = origin; } - Matrix4 _transform; - Offset _origin; - + /// The origin of the coordinate system (relative to the upper left corder of + /// this render object) in which to apply the matrix + /// + /// Setting an origin is equivalent to conjugating the transform matrix by a + /// translation. This property is provided just for convenience. Offset get origin => _origin; + Offset _origin; void set origin (Offset newOrigin) { if (_origin == newOrigin) return; @@ -535,6 +639,10 @@ class RenderTransform extends RenderProxyBox { markNeedsPaint(); } + // Note the lack of a getter for transform because Matrix4 is not immutable + Matrix4 _transform; + + /// The matrix to transform the child by during painting void set transform(Matrix4 newTransform) { assert(newTransform != null); if (_transform == newTransform) @@ -543,31 +651,37 @@ class RenderTransform extends RenderProxyBox { markNeedsPaint(); } + /// Sets the transform to the identity matrix void setIdentity() { _transform.setIdentity(); markNeedsPaint(); } + /// Concatenates a rotation about the x axis into the transform void rotateX(double radians) { _transform.rotateX(radians); markNeedsPaint(); } + /// Concatenates a rotation about the y axis into the transform void rotateY(double radians) { _transform.rotateY(radians); markNeedsPaint(); } + /// Concatenates a rotation about the z axis into the transform void rotateZ(double radians) { _transform.rotateZ(radians); markNeedsPaint(); } + /// Concatenates a translation by (x, y, z) into the transform void translate(x, [double y = 0.0, double z = 0.0]) { _transform.translate(x, y, z); markNeedsPaint(); } + /// Concatenates a scale into the transform void scale(x, [double y, double z]) { _transform.scale(x, y, z); markNeedsPaint(); @@ -611,8 +725,13 @@ class RenderTransform extends RenderProxyBox { } } +/// Called when a size changes typedef void SizeChangedCallback(Size newSize); +/// Calls [callback] whenever the child's layout size changes +/// +/// Note: Size observer calls its callback during layout, which means you cannot +/// dirty layout information during the callback. class RenderSizeObserver extends RenderProxyBox { RenderSizeObserver({ this.callback, @@ -621,20 +740,32 @@ class RenderSizeObserver extends RenderProxyBox { assert(callback != null); } + /// The callback to call whenever the child's layout size changes SizeChangedCallback callback; void performLayout() { Size oldSize = size; - super.performLayout(); - if (oldSize != size) callback(size); } } +/// Called when its time to paint into the given canvas typedef void CustomPaintCallback(PaintingCanvas canvas, Size size); +/// Delegates its painting to [callback] +/// +/// When asked to paint, custom paint first calls its callback with the current +/// canvas and then paints its children. The coodinate system of the canvas +/// matches the coordinate system of the custom paint object. The callback is +/// expected to paint with in a rectangle starting at the origin and +/// encompassing a region of the given size. If the callback paints outside +/// those bounds, there might be insufficient memory allocated to rasterize the +/// painting commands and the resulting behavior is undefined. +/// +/// Note: Custom paint calls its callback during paint, which means you cannot +/// dirty layout or paint information during the callback. class RenderCustomPaint extends RenderProxyBox { RenderCustomPaint({ @@ -645,6 +776,11 @@ class RenderCustomPaint extends RenderProxyBox { _callback = callback; } + /// The callback to which this render object delegates its painting + /// + /// The callback must be non-null whenever the render object is attached to + /// the render tree. + CustomPaintCallback get callback => _callback; CustomPaintCallback _callback; void set callback (CustomPaintCallback newCallback) { assert(newCallback != null || !attached); @@ -670,6 +806,12 @@ class RenderCustomPaint extends RenderProxyBox { } } +/// Is invisible during hit testing +/// +/// When [ignoring] is true, this render object is invisible to hit testing. It +/// still consumes space during layout and paints its child as usual. It just +/// cannot be the target of located events because it returns false from +/// [hitTest]. class RenderIgnorePointer extends RenderProxyBox { RenderIgnorePointer({ RenderBox child, bool ignoring: true }) : super(child); diff --git a/sky/packages/sky/lib/src/widgets/basic.dart b/sky/packages/sky/lib/src/widgets/basic.dart index ce6bc6b7a27..2643c878081 100644 --- a/sky/packages/sky/lib/src/widgets/basic.dart +++ b/sky/packages/sky/lib/src/widgets/basic.dart @@ -292,29 +292,29 @@ class AspectRatio extends OneChildRenderObjectWrapper { } } -class ShrinkWrapWidth extends OneChildRenderObjectWrapper { - ShrinkWrapWidth({ Key key, this.stepWidth, this.stepHeight, Widget child }) +class IntrinsicWidth extends OneChildRenderObjectWrapper { + IntrinsicWidth({ Key key, this.stepWidth, this.stepHeight, Widget child }) : super(key: key, child: child); final double stepWidth; final double stepHeight; - RenderShrinkWrapWidth createNode() => new RenderShrinkWrapWidth(stepWidth: stepWidth, stepHeight: stepHeight); - RenderShrinkWrapWidth get renderObject => super.renderObject; + RenderIntrinsicWidth createNode() => new RenderIntrinsicWidth(stepWidth: stepWidth, stepHeight: stepHeight); + RenderIntrinsicWidth get renderObject => super.renderObject; - void syncRenderObject(ShrinkWrapWidth old) { + void syncRenderObject(IntrinsicWidth old) { super.syncRenderObject(old); renderObject.stepWidth = stepWidth; renderObject.stepHeight = stepHeight; } } -class ShrinkWrapHeight extends OneChildRenderObjectWrapper { - ShrinkWrapHeight({ Key key, Widget child }) +class IntrinsicHeight extends OneChildRenderObjectWrapper { + IntrinsicHeight({ Key key, Widget child }) : super(key: key, child: child); - RenderShrinkWrapHeight createNode() => new RenderShrinkWrapHeight(); - RenderShrinkWrapHeight get renderObject => super.renderObject; + RenderIntrinsicHeight createNode() => new RenderIntrinsicHeight(); + RenderIntrinsicHeight get renderObject => super.renderObject; // Nothing to sync, so we don't implement syncRenderObject() } diff --git a/sky/packages/sky/lib/src/widgets/dialog.dart b/sky/packages/sky/lib/src/widgets/dialog.dart index 713b63577c3..13ed2fabef5 100644 --- a/sky/packages/sky/lib/src/widgets/dialog.dart +++ b/sky/packages/sky/lib/src/widgets/dialog.dart @@ -119,7 +119,7 @@ class Dialog extends Component { child: new Material( level: 4, color: _color, - child: new ShrinkWrapWidth( + child: new IntrinsicWidth( child: new Block(dialogBody) ) ) diff --git a/sky/packages/sky/lib/src/widgets/popup_menu.dart b/sky/packages/sky/lib/src/widgets/popup_menu.dart index b0078de61c2..09b26e6f1d6 100644 --- a/sky/packages/sky/lib/src/widgets/popup_menu.dart +++ b/sky/packages/sky/lib/src/widgets/popup_menu.dart @@ -132,7 +132,7 @@ class PopupMenu extends StatefulComponent { minWidth: _kMenuMinWidth, maxWidth: _kMenuMaxWidth ), - child: new ShrinkWrapWidth( + child: new IntrinsicWidth( stepWidth: _kMenuWidthStep, child: new ScrollableViewport( child: new Container( diff --git a/sky/unit/test/rendering/shrink_wrap_test.dart b/sky/unit/test/rendering/intrinsic_width_test.dart similarity index 94% rename from sky/unit/test/rendering/shrink_wrap_test.dart rename to sky/unit/test/rendering/intrinsic_width_test.dart index 3322d98ee89..e7b636f0322 100644 --- a/sky/unit/test/rendering/shrink_wrap_test.dart +++ b/sky/unit/test/rendering/intrinsic_width_test.dart @@ -35,7 +35,7 @@ void main() { test('Shrink-wrapping width', () { RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); - RenderBox parent = new RenderShrinkWrapWidth(child: child); + RenderBox parent = new RenderIntrinsicWidth(child: child); layout(parent, constraints: new BoxConstraints( minWidth: 5.0, @@ -49,7 +49,7 @@ void main() { test('Shrink-wrapping height', () { RenderBox child = new RenderTestBox(new BoxConstraints(minWidth: 10.0, maxWidth: 100.0, minHeight: 20.0, maxHeight: 200.0)); - RenderBox parent = new RenderShrinkWrapHeight(child: child); + RenderBox parent = new RenderIntrinsicHeight(child: child); layout(parent, constraints: new BoxConstraints( minWidth: 5.0,