diff --git a/examples/rendering/sector_layout.dart b/examples/rendering/sector_layout.dart index 5bde7213cc9da905cc3aa4208d8c72a18a428e19..0f6a4b024240298fd590e4083d3c665cff4231fb 100644 --- a/examples/rendering/sector_layout.dart +++ b/examples/rendering/sector_layout.dart @@ -452,7 +452,7 @@ class RenderBoxToRenderSectorAdapter extends RenderBox { Size getIntrinsicDimensions(BoxConstraints constraints) { assert(child is RenderSector); assert(child.parentData is SectorParentData); - assert(!constraints.isInfinite); + assert(constraints.maxWidth < double.INFINITY || constraints.maxHeight < double.INFINITY); double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxHeight) / 2.0 - innerRadius; SectorDimensions childDimensions = child.getIntrinsicDimensions(new SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), innerRadius); double dimension = (innerRadius + childDimensions.deltaRadius) * 2.0; @@ -464,7 +464,7 @@ class RenderBoxToRenderSectorAdapter extends RenderBox { size = constraints.constrain(Size.zero); } else { assert(child is RenderSector); - assert(!constraints.isInfinite); + assert(constraints.maxWidth < double.INFINITY || constraints.maxHeight < double.INFINITY); double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxHeight) / 2.0 - innerRadius; assert(child.parentData is SectorParentData); child.parentData.radius = innerRadius; diff --git a/examples/widgets/styled_text.dart b/examples/widgets/styled_text.dart index a4abdc828d683b1737b66ab46f9970a4bf108449..38fcb0d0b02382b0488687c432615a74af7e276a 100644 --- a/examples/widgets/styled_text.dart +++ b/examples/widgets/styled_text.dart @@ -53,7 +53,7 @@ HAL: This mission is too important for me to allow you to jeopardize it.'''; Component createSeparator() { return new Container( - constraints: const BoxConstraints.expandWidth(maxHeight: 0.0), + constraints: const BoxConstraints.expand(height: 0.0), margin: const EdgeDims.symmetric(vertical: 10.0, horizontal: 64.0), decoration: const BoxDecoration( border: const Border( diff --git a/sky/packages/sky/lib/src/rendering/block.dart b/sky/packages/sky/lib/src/rendering/block.dart index 994c81d29259c7ba48d0a88985d66835a7953c62..4c4ad2baaf0af60b734b5849c721d0077a72323e 100644 --- a/sky/packages/sky/lib/src/rendering/block.dart +++ b/sky/packages/sky/lib/src/rendering/block.dart @@ -314,7 +314,7 @@ class RenderBlockViewport extends RenderBlockBase { double getMaxIntrinsicWidth(BoxConstraints constraints) { if (isVertical) return _getIntrinsicDimension(constraints, maxCrossAxisDimensionCallback, constraints.constrainWidth); - return _getIntrinsicDimension(constraints, totalExtentCallback, new BoxConstraints(minWidth: minExtent).apply(constraints).constrainWidth); + return _getIntrinsicDimension(constraints, totalExtentCallback, new BoxConstraints(minWidth: minExtent).enforce(constraints).constrainWidth); } double getMinIntrinsicHeight(BoxConstraints constraints) { @@ -326,7 +326,7 @@ class RenderBlockViewport extends RenderBlockBase { double getMaxIntrinsicHeight(BoxConstraints constraints) { if (!isVertical) return _getIntrinsicDimension(constraints, maxCrossAxisDimensionCallback, constraints.constrainHeight); - return _getIntrinsicDimension(constraints, totalExtentCallback, new BoxConstraints(minHeight: minExtent).apply(constraints).constrainHeight); + return _getIntrinsicDimension(constraints, totalExtentCallback, new BoxConstraints(minHeight: minExtent).enforce(constraints).constrainHeight); } // We don't override computeDistanceToActualBaseline(), because we diff --git a/sky/packages/sky/lib/src/rendering/box.dart b/sky/packages/sky/lib/src/rendering/box.dart index 9bf50072d5d2a1e291f77904523fdc95bdf7acd1..8155de97dd7c3c4aa994dfc0c0d5a6df9eb39831 100644 --- a/sky/packages/sky/lib/src/rendering/box.dart +++ b/sky/packages/sky/lib/src/rendering/box.dart @@ -23,7 +23,22 @@ class _DebugSize extends Size { final bool _canBeUsedByParent; } +/// Immutable layout constraints for box layout +/// +/// A size respects a BoxConstraints if, and only if, all of the following +/// relations hold: +/// +/// * `minWidth <= size.width <= constraints.maxWidth` +/// * `minHeight <= size.height <= maxHeight` +/// +/// The constraints themselves must satisfy these relations: +/// +/// * `0.0 <= minWidth <= maxWidth <= double.INFINITY` +/// * `0.0 <= minHeight <= maxHeight <= double.INFINITY` +/// +/// Note: `double.INFINITY` is a legal value for each constraint. class BoxConstraints extends Constraints { + /// Constructs box constraints with the given constraints const BoxConstraints({ this.minWidth: 0.0, this.maxWidth: double.INFINITY, @@ -31,12 +46,19 @@ class BoxConstraints extends Constraints { this.maxHeight: double.INFINITY }); + final double minWidth; + final double maxWidth; + final double minHeight; + final double maxHeight; + + /// Constructs box constraints that is respected only by the given size BoxConstraints.tight(Size size) : minWidth = size.width, maxWidth = size.width, minHeight = size.height, maxHeight = size.height; + /// Constructs box constraints that require the given width or height const BoxConstraints.tightFor({ double width, double height @@ -45,43 +67,41 @@ class BoxConstraints extends Constraints { minHeight = height != null ? height : 0.0, maxHeight = height != null ? height : double.INFINITY; + /// Constructs box constraints that forbid sizes larger than the given size BoxConstraints.loose(Size size) : minWidth = 0.0, maxWidth = size.width, minHeight = 0.0, maxHeight = size.height; - const BoxConstraints.expandWidth({ - this.maxHeight: double.INFINITY - }): minWidth = double.INFINITY, - maxWidth = double.INFINITY, - minHeight = 0.0; - - const BoxConstraints.expandHeight({ - this.maxWidth: double.INFINITY - }): minWidth = 0.0, - minHeight = double.INFINITY, - maxHeight = double.INFINITY; - - static const BoxConstraints expand = const BoxConstraints( - minWidth: double.INFINITY, - maxWidth: double.INFINITY, - minHeight: double.INFINITY, - maxHeight: double.INFINITY - ); - + /// Constructs box constraints that expand to fill another box contraints + /// + /// If width or height is given, the constraints will require exactly the + /// given value in the given dimension. + const BoxConstraints.expand({ + double width, + double height + }): minWidth = width != null ? width : double.INFINITY, + maxWidth = width != null ? width : double.INFINITY, + minHeight = height != null ? height : double.INFINITY, + maxHeight = height != null ? height : double.INFINITY; + + /// Returns new box constraints that are smaller by the given edge dimensions BoxConstraints deflate(EdgeDims edges) { assert(edges != null); double horizontal = edges.left + edges.right; double vertical = edges.top + edges.bottom; + double deflatedMinWidth = math.max(0.0, minWidth - horizontal); + double deflatedMinHeight = math.max(0.0, minHeight - vertical); return new BoxConstraints( - minWidth: math.max(0.0, minWidth - horizontal), - maxWidth: maxWidth - horizontal, - minHeight: math.max(0.0, minHeight - vertical), - maxHeight: maxHeight - vertical + minWidth: deflatedMinWidth, + maxWidth: math.max(deflatedMinWidth, maxWidth - horizontal), + minHeight: deflatedMinHeight, + maxHeight: math.max(deflatedMinHeight, maxHeight - vertical) ); } + /// Returns new box constraints that remove the minimum width and height requirements BoxConstraints loosen() { return new BoxConstraints( minWidth: 0.0, @@ -91,7 +111,8 @@ class BoxConstraints extends Constraints { ); } - BoxConstraints apply(BoxConstraints constraints) { + /// Returns new box constraints that respect the given constraints while being as close as possible to the original constraints + BoxConstraints enforce(BoxConstraints constraints) { return new BoxConstraints( minWidth: clamp(min: constraints.minWidth, max: constraints.maxWidth, value: minWidth), maxWidth: clamp(min: constraints.minWidth, max: constraints.maxWidth, value: maxWidth), @@ -100,81 +121,63 @@ class BoxConstraints extends Constraints { ); } - BoxConstraints applyWidth(double width) { + /// Returns new box constraints with a tight width as close to the given width as possible while still respecting the original box constraints + BoxConstraints tightenWidth(double width) { return new BoxConstraints(minWidth: math.max(math.min(maxWidth, width), minWidth), maxWidth: math.max(math.min(maxWidth, width), minWidth), minHeight: minHeight, maxHeight: maxHeight); } - BoxConstraints applyMinWidth(double newMinWidth) { - return new BoxConstraints(minWidth: math.max(minWidth, newMinWidth), - maxWidth: math.max(maxWidth, newMinWidth), - minHeight: minHeight, - maxHeight: maxHeight); - } - - BoxConstraints applyMaxWidth(double newMaxWidth) { - return new BoxConstraints(minWidth: minWidth, - maxWidth: math.min(maxWidth, newMaxWidth), - minHeight: minHeight, - maxHeight: maxHeight); - } - - BoxConstraints applyHeight(double height) { + /// Returns new box constraints with a tight height as close to the given height as possible while still respecting the original box constraints + BoxConstraints tightenHeight(double height) { return new BoxConstraints(minWidth: minWidth, maxWidth: maxWidth, minHeight: math.max(math.min(maxHeight, height), minHeight), maxHeight: math.max(math.min(maxHeight, height), minHeight)); } - BoxConstraints applyMinHeight(double newMinHeight) { - return new BoxConstraints(minWidth: minWidth, - maxWidth: maxWidth, - minHeight: math.max(minHeight, newMinHeight), - maxHeight: math.max(maxHeight, newMinHeight)); - } - - BoxConstraints applyMaxHeight(double newMaxHeight) { - return new BoxConstraints(minWidth: minWidth, - maxWidth: maxWidth, - minHeight: minHeight, - maxHeight: math.min(maxHeight, newMaxHeight)); - } - + /// Returns box constraints with the same width constraints but with unconstrainted height BoxConstraints widthConstraints() => new BoxConstraints(minWidth: minWidth, maxWidth: maxWidth); + /// Returns box constraints with the same height constraints but with unconstrainted width BoxConstraints heightConstraints() => new BoxConstraints(minHeight: minHeight, maxHeight: maxHeight); - final double minWidth; - final double maxWidth; - final double minHeight; - final double maxHeight; - + /// Returns the width that both satisfies the constraints and is as close as possible to the given width double constrainWidth([double width = double.INFINITY]) { return clamp(min: minWidth, max: maxWidth, value: width); } + /// Returns the height that both satisfies the constraints and is as close as possible to the given height double constrainHeight([double height = double.INFINITY]) { return clamp(min: minHeight, max: maxHeight, value: height); } + /// Returns the size that both satisfies the constraints and is as close as possible to the given size Size constrain(Size size) { Size result = new Size(constrainWidth(size.width), constrainHeight(size.height)); if (size is _DebugSize) result = new _DebugSize(result, size._owner, size._canBeUsedByParent); return result; } + + /// The biggest size that satisifes the constraints Size get biggest => new Size(constrainWidth(), constrainHeight()); - Size get smallest => new Size(constrainWidth(0.0), constrainHeight(0.0)); - bool get isInfinite => maxWidth >= double.INFINITY && maxHeight >= double.INFINITY; + /// The smallest size that satisfies the constraints + Size get smallest => new Size(constrainWidth(0.0), constrainHeight(0.0)); + /// Whether there is exactly one width value that satisfies the constraints bool get hasTightWidth => minWidth >= maxWidth; + + /// Whether there is exactly one height value that satisfies the constraints bool get hasTightHeight => minHeight >= maxHeight; + + /// Whether there is exactly one size that satifies the constraints bool get isTight => hasTightWidth && hasTightHeight; - bool contains(Size size) { + /// Whether the given size satisfies the constraints + bool isSatisfiedBy(Size size) { return (minWidth <= size.width) && (size.width <= math.max(minWidth, maxWidth)) && (minHeight <= size.height) && (size.height <= math.max(minHeight, maxHeight)); } @@ -323,7 +326,7 @@ abstract class RenderBox extends RenderObject { 'See https://github.com/domokit/sky_engine/blob/master/sky/packages/sky/lib/src/widgets/sizing.md#user-content-unbounded-constraints'; return !_size.isInfinite; }); - bool result = constraints.contains(_size); + bool result = constraints.isSatisfiedBy(_size); if (!result) print("${this.runtimeType} does not meet its constraints. Constraints: $constraints, size: $_size"); return result; diff --git a/sky/packages/sky/lib/src/rendering/image.dart b/sky/packages/sky/lib/src/rendering/image.dart index e3eb3a1ad1aba8be4c50bb7b98cb7411b51f6d27..a1ff0c50867b4795179dfa08a570c9013e484138 100644 --- a/sky/packages/sky/lib/src/rendering/image.dart +++ b/sky/packages/sky/lib/src/rendering/image.dart @@ -85,7 +85,7 @@ class RenderImage extends RenderBox { constraints = new BoxConstraints.tightFor( width: _width, height: _height - ).apply(constraints); + ).enforce(constraints); if (constraints.isTight || _image == null) return constraints.smallest; diff --git a/sky/packages/sky/lib/src/rendering/proxy_box.dart b/sky/packages/sky/lib/src/rendering/proxy_box.dart index 0a148f5393b2a55ec0dea7022bd2e7c2fadad950..a95917142d74a9e9f417d1fa09bc9ed41915367a 100644 --- a/sky/packages/sky/lib/src/rendering/proxy_box.dart +++ b/sky/packages/sky/lib/src/rendering/proxy_box.dart @@ -92,34 +92,34 @@ class RenderConstrainedBox extends RenderProxyBox { double getMinIntrinsicWidth(BoxConstraints constraints) { if (child != null) - return child.getMinIntrinsicWidth(_additionalConstraints.apply(constraints)); - return _additionalConstraints.apply(constraints).constrainWidth(0.0); + return child.getMinIntrinsicWidth(_additionalConstraints.enforce(constraints)); + return _additionalConstraints.enforce(constraints).constrainWidth(0.0); } double getMaxIntrinsicWidth(BoxConstraints constraints) { if (child != null) - return child.getMaxIntrinsicWidth(_additionalConstraints.apply(constraints)); - return _additionalConstraints.apply(constraints).constrainWidth(0.0); + return child.getMaxIntrinsicWidth(_additionalConstraints.enforce(constraints)); + return _additionalConstraints.enforce(constraints).constrainWidth(0.0); } double getMinIntrinsicHeight(BoxConstraints constraints) { if (child != null) - return child.getMinIntrinsicHeight(_additionalConstraints.apply(constraints)); - return _additionalConstraints.apply(constraints).constrainHeight(0.0); + return child.getMinIntrinsicHeight(_additionalConstraints.enforce(constraints)); + return _additionalConstraints.enforce(constraints).constrainHeight(0.0); } double getMaxIntrinsicHeight(BoxConstraints constraints) { if (child != null) - return child.getMaxIntrinsicHeight(_additionalConstraints.apply(constraints)); - return _additionalConstraints.apply(constraints).constrainHeight(0.0); + return child.getMaxIntrinsicHeight(_additionalConstraints.enforce(constraints)); + return _additionalConstraints.enforce(constraints).constrainHeight(0.0); } void performLayout() { if (child != null) { - child.layout(_additionalConstraints.apply(constraints), parentUsesSize: true); + child.layout(_additionalConstraints.enforce(constraints), parentUsesSize: true); size = child.size; } else { - size = _additionalConstraints.apply(constraints).constrain(Size.zero); + size = _additionalConstraints.enforce(constraints).constrain(Size.zero); } } @@ -218,7 +218,7 @@ class RenderShrinkWrapWidth extends RenderProxyBox { return constraints; double width = child.getMaxIntrinsicWidth(constraints); assert(width == constraints.constrainWidth(width)); - return constraints.applyWidth(applyStep(width, _stepWidth)); + return constraints.tightenWidth(applyStep(width, _stepWidth)); } double getMinIntrinsicWidth(BoxConstraints constraints) { @@ -250,7 +250,7 @@ class RenderShrinkWrapWidth extends RenderProxyBox { if (child != null) { BoxConstraints childConstraints = _getInnerConstraints(constraints); if (_stepHeight != null) - childConstraints.applyHeight(getMaxIntrinsicHeight(childConstraints)); + childConstraints.tightenHeight(getMaxIntrinsicHeight(childConstraints)); child.layout(childConstraints, parentUsesSize: true); size = child.size; } else { @@ -281,7 +281,7 @@ class RenderShrinkWrapHeight extends RenderProxyBox { return constraints; double height = child.getMaxIntrinsicHeight(constraints); assert(height == constraints.constrainHeight(height)); - return constraints.applyHeight(height); + return constraints.tightenHeight(height); } double getMinIntrinsicWidth(BoxConstraints constraints) { diff --git a/sky/packages/sky/lib/src/rendering/stack.dart b/sky/packages/sky/lib/src/rendering/stack.dart index 4ee6eb55e0e50f79fc72d91d5d1803897312e2a2..584e4d8902599bee1fb4b88fe10f64bea053830b 100644 --- a/sky/packages/sky/lib/src/rendering/stack.dart +++ b/sky/packages/sky/lib/src/rendering/stack.dart @@ -155,10 +155,10 @@ class RenderStack extends RenderBox with ContainerRenderObjectMixin