public void layout(IFigure parent) {
List<IFigure> children = parent.getChildren();
int numChildren = children.size();
Rectangle clientArea = transposer.t(parent.getClientArea());
Insets margins = transposer.t(this.marginInsets);
clientArea.x += margins.left;
clientArea.width -= (margins.left + margins.right);
int x = clientArea.x;
int y = clientArea.y;
int availableHeight = clientArea.height;
Dimension prefSizes[] = new Dimension[numChildren];
Dimension minSizes[] = new Dimension[numChildren];
Dimension maxCellSizes[] = new Dimension[numChildren];
Dimension maxChildShapeSizes[] = new Dimension[numChildren];
int extraHeights[] = new int[numChildren];
SapphireSequenceLayoutConstraint constraints[] = new SapphireSequenceLayoutConstraint[numChildren];
Insets marginInsets[] = new Insets[numChildren];
// Calculate the width and height hints. If it's a vertical sequence layout,
// then ignore the height hint (set it to -1); otherwise, ignore the
// width hint. These hints will be passed to the children of the parent
// figure when getting their preferred size.
int wHint = -1;
int hHint = -1;
if (isHorizontal()) {
hHint = parent.getClientArea(Rectangle.SINGLETON).height - (margins.top + margins.bottom);
} else {
wHint = parent.getClientArea(Rectangle.SINGLETON).width - (margins.left + margins.right);
}
/*
* Calculate sum of preferred heights of all children(totalHeight).
* Cache Preferred Sizes and Minimum Sizes of all children.
*/
IFigure child;
int totalHeight = 0;
int totalMinHeight = 0;
int prefMinSumHeight = 0;
int totalMargin = 0;
int expandCount = 0;
for (int i = 0; i < numChildren; i++) {
child = children.get(i);
SapphireSequenceLayoutConstraint constraint = (SapphireSequenceLayoutConstraint)getConstraint(child);
if (constraint == null)
setConstraint(child, constraint = new SapphireSequenceLayoutConstraint());
constraints[i] = constraint;
prefSizes[i] = transposer.t(getChildPreferredSize(child, wHint, hHint));
minSizes[i] = transposer.t(getChildMinimumSize(child, wHint, hHint));
maxCellSizes[i] = transposer.t(getChildCellMaximumSize(child));
maxChildShapeSizes[i] = transposer.t(child.getMaximumSize());
marginInsets[i] = transposer.t(constraint.getMarginInset());
totalHeight += prefSizes[i].height;
totalMinHeight += minSizes[i].height;
totalMargin += marginInsets[i].top + marginInsets[i].bottom;
// We need to expand the cell if the its constraint has "expand" bit on or
// one of the children has "expand" bit on
if (getMajorExpand(constraint) || maxChildShapeSizes[i].height > prefSizes[i].height) {
expandCount++;
}
}
totalHeight += (numChildren - 1) * spacing;
totalHeight += totalMargin + margins.top + margins.bottom;
totalMinHeight += (numChildren - 1) * spacing;
totalMinHeight += totalMargin + margins.top + margins.bottom;
prefMinSumHeight = totalHeight - totalMinHeight;
int amntShrinkHeight = totalHeight
- Math.max(availableHeight, totalMinHeight);
int extraHeight = -amntShrinkHeight;
if (amntShrinkHeight < 0) {
amntShrinkHeight = 0;
}
if (extraHeight <= 0) {
extraHeight = 0;
} else if (expandCount > 0) {
int averageExtraHeight = extraHeight / expandCount;
int limitedExpansionCount = 0;
int limitedExpansionHeightTotal = 0;
if (expandCount > 1) {
for (int i = 0; i < numChildren; i++) {
int prefHeight = prefSizes[i].height;
int maxCellHeight = maxCellSizes[i].height;
child = children.get(i);
SapphireSequenceLayoutConstraint constraint = constraints[i];
if (getMajorExpand(constraint) || maxCellHeight > prefHeight) {
// only limited expansion since the child figure has max size constraint.
if (maxCellHeight - prefHeight < averageExtraHeight) {
limitedExpansionCount++;
limitedExpansionHeightTotal += maxCellHeight - prefHeight;
}
}
}
}
int unlimitedExpansionAverage = limitedExpansionCount < expandCount ?
(extraHeight - limitedExpansionHeightTotal) / (expandCount - limitedExpansionCount) : 0;
for (int i = 0; i < numChildren; i++) {
int prefHeight = prefSizes[i].height;
int maxCellHeight = maxCellSizes[i].height;
child = children.get(i);
SapphireSequenceLayoutConstraint constraint = constraints[i];
if (getMajorExpand(constraint) || maxCellHeight > prefHeight) {
// only limited expansion
if (expandCount > 1 && (maxCellHeight - prefHeight < averageExtraHeight)) {
extraHeights[i] = maxCellHeight - prefHeight;
}
else {
extraHeights[i] = unlimitedExpansionAverage;
}
}
else {
extraHeights[i] = 0;
}
}
}
y += margins.top;
for (int i = 0; i < numChildren; i++) {
int amntShrinkCurrentHeight = 0;
child = children.get(i);
int prefHeight = prefSizes[i].height;
int minHeight = minSizes[i].height;
int prefWidth = prefSizes[i].width;
int minWidth = minSizes[i].width;
Insets marginInset = marginInsets[i];
Rectangle newBounds, availableBounds;
int availableBoundHeight;
SapphireSequenceLayoutConstraint constraint = constraints[i];
if (prefMinSumHeight != 0)