| // 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:sky/painting/box_painter.dart'; |
| import 'package:sky/painting/text_style.dart'; |
| import 'package:sky/rendering/object.dart'; |
| import 'package:sky/rendering/box.dart'; |
| |
| abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixin<RenderBox> { |
| |
| // Abstract class for one-child-layout render boxes |
| |
| RenderShiftedBox(RenderBox child) { |
| this.child = child; |
| } |
| |
| double getMinIntrinsicWidth(BoxConstraints constraints) { |
| if (child != null) |
| return child.getMinIntrinsicWidth(constraints); |
| return super.getMinIntrinsicWidth(constraints); |
| } |
| |
| double getMaxIntrinsicWidth(BoxConstraints constraints) { |
| if (child != null) |
| return child.getMaxIntrinsicWidth(constraints); |
| return super.getMaxIntrinsicWidth(constraints); |
| } |
| |
| double getMinIntrinsicHeight(BoxConstraints constraints) { |
| if (child != null) |
| return child.getMinIntrinsicHeight(constraints); |
| return super.getMinIntrinsicHeight(constraints); |
| } |
| |
| double getMaxIntrinsicHeight(BoxConstraints constraints) { |
| if (child != null) |
| return child.getMaxIntrinsicHeight(constraints); |
| return super.getMaxIntrinsicHeight(constraints); |
| } |
| |
| double computeDistanceToActualBaseline(TextBaseline baseline) { |
| double result; |
| if (child != null) { |
| assert(!needsLayout); |
| result = child.getDistanceToActualBaseline(baseline); |
| assert(child.parentData is BoxParentData); |
| if (result != null) |
| result += child.parentData.position.y; |
| } else { |
| result = super.computeDistanceToActualBaseline(baseline); |
| } |
| return result; |
| } |
| |
| void paint(PaintingContext context, Offset offset) { |
| if (child != null) |
| context.paintChild(child, child.parentData.position + offset); |
| } |
| |
| void hitTestChildren(HitTestResult result, { Point position }) { |
| if (child != null) { |
| assert(child.parentData is BoxParentData); |
| child.hitTest(result, position: new Point(position.x - child.parentData.position.x, |
| position.y - child.parentData.position.y)); |
| } |
| } |
| |
| } |
| |
| class RenderPadding extends RenderShiftedBox { |
| |
| RenderPadding({ EdgeDims padding, RenderBox child }) : super(child) { |
| assert(padding != null); |
| this.padding = padding; |
| } |
| |
| EdgeDims _padding; |
| EdgeDims get padding => _padding; |
| void set padding (EdgeDims value) { |
| assert(value != null); |
| if (_padding == value) |
| return; |
| _padding = value; |
| markNeedsLayout(); |
| } |
| |
| double getMinIntrinsicWidth(BoxConstraints constraints) { |
| double totalPadding = padding.left + padding.right; |
| if (child != null) |
| return child.getMinIntrinsicWidth(constraints.deflate(padding)) + totalPadding; |
| return constraints.constrainWidth(totalPadding); |
| } |
| |
| double getMaxIntrinsicWidth(BoxConstraints constraints) { |
| double totalPadding = padding.left + padding.right; |
| if (child != null) |
| return child.getMaxIntrinsicWidth(constraints.deflate(padding)) + totalPadding; |
| return constraints.constrainWidth(totalPadding); |
| } |
| |
| double getMinIntrinsicHeight(BoxConstraints constraints) { |
| double totalPadding = padding.top + padding.bottom; |
| if (child != null) |
| return child.getMinIntrinsicHeight(constraints.deflate(padding)) + totalPadding; |
| return constraints.constrainHeight(totalPadding); |
| } |
| |
| double getMaxIntrinsicHeight(BoxConstraints constraints) { |
| double totalPadding = padding.top + padding.bottom; |
| if (child != null) |
| return child.getMaxIntrinsicHeight(constraints.deflate(padding)) + totalPadding; |
| return constraints.constrainHeight(totalPadding); |
| } |
| |
| void performLayout() { |
| assert(padding != null); |
| if (child == null) { |
| size = constraints.constrain(new Size( |
| padding.left + padding.right, |
| padding.top + padding.bottom |
| )); |
| return; |
| } |
| BoxConstraints innerConstraints = constraints.deflate(padding); |
| child.layout(innerConstraints, parentUsesSize: true); |
| assert(child.parentData is BoxParentData); |
| child.parentData.position = new Point(padding.left, padding.top); |
| size = constraints.constrain(new Size( |
| padding.left + child.size.width + padding.right, |
| padding.top + child.size.height + padding.bottom |
| )); |
| } |
| |
| String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}padding: ${padding}\n'; |
| } |
| |
| class RenderPositionedBox extends RenderShiftedBox { |
| |
| // This box aligns a child box within itself. It's only useful for |
| // children that don't always size to fit their parent. For example, |
| // to align a box at the bottom right, you would pass this box a |
| // tight constraint that is bigger than the child's natural size, |
| // with horizontal and vertical set to 1.0. |
| |
| RenderPositionedBox({ |
| RenderBox child, |
| double horizontal: 0.5, |
| double vertical: 0.5 |
| }) : _horizontal = horizontal, |
| _vertical = vertical, |
| super(child) { |
| assert(horizontal != null); |
| assert(vertical != null); |
| } |
| |
| double _horizontal; |
| double get horizontal => _horizontal; |
| void set horizontal (double value) { |
| assert(value != null); |
| if (_horizontal == value) |
| return; |
| _horizontal = value; |
| markNeedsLayout(); |
| } |
| |
| double _vertical; |
| double get vertical => _vertical; |
| void set vertical (double value) { |
| assert(value != null); |
| if (_vertical == value) |
| return; |
| _vertical = value; |
| markNeedsLayout(); |
| } |
| |
| void performLayout() { |
| if (child != null) { |
| child.layout(constraints.loosen(), parentUsesSize: true); |
| size = constraints.constrain(child.size); |
| assert(child.parentData is BoxParentData); |
| Offset delta = size - child.size; |
| child.parentData.position = (delta.scale(horizontal, vertical)).toPoint(); |
| } else { |
| performResize(); |
| } |
| } |
| |
| String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}horizontal: ${horizontal}\n${prefix}vertical: ${vertical}\n'; |
| } |
| |
| class RenderBaseline extends RenderShiftedBox { |
| |
| RenderBaseline({ |
| RenderBox child, |
| double baseline, |
| TextBaseline baselineType |
| }) : _baseline = baseline, |
| _baselineType = baselineType, |
| super(child) { |
| assert(baseline != null); |
| assert(baselineType != null); |
| } |
| |
| double _baseline; |
| double get baseline => _baseline; |
| void set baseline (double value) { |
| assert(value != null); |
| if (_baseline == value) |
| return; |
| _baseline = value; |
| markNeedsLayout(); |
| } |
| |
| TextBaseline _baselineType; |
| TextBaseline get baselineType => _baselineType; |
| void set baselineType (TextBaseline value) { |
| assert(value != null); |
| if (_baselineType == value) |
| return; |
| _baselineType = value; |
| markNeedsLayout(); |
| } |
| |
| void performLayout() { |
| if (child != null) { |
| child.layout(constraints.loosen(), parentUsesSize: true); |
| size = constraints.constrain(child.size); |
| assert(child.parentData is BoxParentData); |
| double delta = baseline - child.getDistanceToBaseline(baselineType); |
| child.parentData.position = new Point(0.0, delta); |
| } else { |
| performResize(); |
| } |
| } |
| |
| String debugDescribeSettings(String prefix) => '${super.debugDescribeSettings(prefix)}${prefix}baseline: ${baseline}\nbaselineType: ${baselineType}'; |
| } |