Adam Barth d0240c4eae Remove ParentData#merge
There aren't any clients anymore.

Fixes #1684
2016-02-08 16:58:39 -08:00

172 lines
5.8 KiB
Dart

// 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';
// For OneChildLayoutDelegate and RenderCustomOneChildLayoutBox, see shifted_box.dart
class MultiChildLayoutParentData extends ContainerBoxParentDataMixin<RenderBox> {
/// An object representing the identity of this child.
Object id;
String toString() => '${super.toString()}; id=$id';
}
/// A delegate that controls the layout of multiple children.
abstract class MultiChildLayoutDelegate {
Map<Object, RenderBox> _idToChild;
Set<RenderBox> _debugChildrenNeedingLayout;
/// Returns the size of this object given the incoming constraints.
/// The size cannot reflect the instrinsic sizes of the children.
/// If this layout has a fixed width or height the returned size
/// can reflect that.
Size getSize(BoxConstraints constraints) => constraints.biggest;
/// True if a non-null LayoutChild was provided for the specified id.
bool isChild(Object childId) => _idToChild[childId] != null;
/// Ask the child to update its layout within the limits specified by
/// the constraints parameter. The child's size is returned.
Size layoutChild(Object childId, BoxConstraints constraints) {
final RenderBox child = _idToChild[childId];
assert(child != null);
assert(() {
'A MultiChildLayoutDelegate cannot layout the same child more than once.';
return _debugChildrenNeedingLayout.remove(child);
});
assert(constraints.isNormalized);
child.layout(constraints, parentUsesSize: true);
return child.size;
}
/// Specify the child's origin relative to this origin.
void positionChild(Object childId, Offset offset) {
final RenderBox child = _idToChild[childId];
assert(child != null);
final MultiChildLayoutParentData childParentData = child.parentData;
childParentData.offset = offset;
}
void _callPerformLayout(Size size, BoxConstraints constraints, RenderBox firstChild) {
final Map<Object, RenderBox> previousIdToChild = _idToChild;
Set<RenderBox> debugPreviousChildrenNeedingLayout;
assert(() {
debugPreviousChildrenNeedingLayout = _debugChildrenNeedingLayout;
_debugChildrenNeedingLayout = new Set<RenderBox>();
return true;
});
try {
_idToChild = new Map<Object, RenderBox>();
RenderBox child = firstChild;
while (child != null) {
final MultiChildLayoutParentData childParentData = child.parentData;
assert(childParentData.id != null);
_idToChild[childParentData.id] = child;
assert(() {
_debugChildrenNeedingLayout.add(child);
return true;
});
child = childParentData.nextSibling;
}
performLayout(size, constraints);
assert(() {
'A MultiChildLayoutDelegate needs to call layoutChild on every child.';
return _debugChildrenNeedingLayout.isEmpty;
});
} finally {
_idToChild = previousIdToChild;
assert(() {
_debugChildrenNeedingLayout = debugPreviousChildrenNeedingLayout;
return true;
});
}
}
/// Override this method to return true when the children need to be laid out.
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate);
/// Layout and position all children given this widget's size and the specified
/// constraints. This method must apply layoutChild() to each child. It should
/// specify the final position of each child with positionChild().
void performLayout(Size size, BoxConstraints constraints);
}
/// Defers the layout of multiple children to a delegate.
///
/// The delegate can determine the layout constraints for each child and can
/// decide where to position each child. The delegate can also determine the
/// size of the parent, but the size of the parent cannot depend on the sizes of
/// the children.
class RenderCustomMultiChildLayoutBox extends RenderBox
with ContainerRenderObjectMixin<RenderBox, MultiChildLayoutParentData>,
RenderBoxContainerDefaultsMixin<RenderBox, MultiChildLayoutParentData> {
RenderCustomMultiChildLayoutBox({
List<RenderBox> children,
MultiChildLayoutDelegate delegate
}) : _delegate = delegate {
assert(delegate != null);
addAll(children);
}
void setupParentData(RenderBox child) {
if (child.parentData is! MultiChildLayoutParentData)
child.parentData = new MultiChildLayoutParentData();
}
/// The delegate that controls the layout of the children.
MultiChildLayoutDelegate get delegate => _delegate;
MultiChildLayoutDelegate _delegate;
void set delegate (MultiChildLayoutDelegate newDelegate) {
assert(newDelegate != null);
if (_delegate == newDelegate)
return;
if (newDelegate.runtimeType != _delegate.runtimeType || newDelegate.shouldRelayout(_delegate))
markNeedsLayout();
_delegate = newDelegate;
}
Size _getSize(BoxConstraints constraints) {
assert(constraints.isNormalized);
return constraints.constrain(_delegate.getSize(constraints));
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
return _getSize(constraints).width;
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
return _getSize(constraints).width;
}
double getMinIntrinsicHeight(BoxConstraints constraints) {
return _getSize(constraints).height;
}
double getMaxIntrinsicHeight(BoxConstraints constraints) {
return _getSize(constraints).height;
}
bool get sizedByParent => true;
void performResize() {
size = _getSize(constraints);
}
void performLayout() {
delegate._callPerformLayout(size, constraints, firstChild);
}
void paint(PaintingContext context, Offset offset) {
defaultPaint(context, offset);
}
bool hitTestChildren(HitTestResult result, { Point position }) {
return defaultHitTestChildren(result, position: position);
}
}