package de.lessvoid.nifty.layout.manager;
import de.lessvoid.nifty.layout.Box;
import de.lessvoid.nifty.layout.BoxConstraints;
import de.lessvoid.nifty.layout.LayoutPart;
import de.lessvoid.nifty.layout.align.VerticalAlign;
import de.lessvoid.nifty.tools.SizeValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
/**
* A HorizontalLayout implementation of the LayoutManager interface.
* The children elements are arranged in a horizontal form
* in relation to the root element.
*
* @author void
*/
public class HorizontalLayout implements LayoutManager {
/**
* Layout the elements.
*
* @param root the root element
* @param children the children
*/
@Override
public final void layoutElements(@Nonnull final LayoutPart root, @Nonnull final List<LayoutPart> children) {
if (isInvalid(root, children)) {
return;
}
int rootBoxX = getRootBoxX(root);
int rootBoxY = getRootBoxY(root);
int rootBoxWidth = getRootBoxWidth(root);
int rootBoxHeight = getRootBoxHeight(root);
int x = rootBoxX;
for (int i = 0; i < children.size(); i++) {
LayoutPart current = children.get(i);
Box box = current.getBox();
BoxConstraints boxConstraints = current.getBoxConstraints();
int elementWidth;
if (boxConstraints.getWidth().hasHeightSuffix()) {
int elementHeight = processHeightConstraint(rootBoxHeight, box, boxConstraints, 0);
box.setHeight(elementHeight);
elementWidth = calcElementWidth(children, rootBoxWidth, boxConstraints, elementHeight);
box.setWidth(elementWidth);
} else if (hasHeightConstraint(boxConstraints) && boxConstraints.getHeight().hasWidthSuffix()) {
elementWidth = calcElementWidth(children, rootBoxWidth, boxConstraints, 0);
box.setWidth(elementWidth);
int elementHeight = processHeightConstraint(rootBoxHeight, box, boxConstraints, elementWidth);
box.setHeight(elementHeight);
} else {
elementWidth = calcElementWidth(children, rootBoxWidth, boxConstraints, 0);
box.setWidth(elementWidth);
int elementHeight = processHeightConstraint(rootBoxHeight, box, boxConstraints, 0);
box.setHeight(elementHeight);
}
int y = processVerticalAlignment(rootBoxY, rootBoxHeight, box, boxConstraints);
y = y + topMargin(boxConstraints, rootBoxHeight);
box.setY(y);
x = x + leftMargin(boxConstraints, rootBoxWidth);
box.setX(x);
x += elementWidth + rightMargin(boxConstraints, rootBoxWidth);
}
}
private int leftMargin(@Nonnull final BoxConstraints boxConstraints, final int rootBoxWidth) {
return boxConstraints.getMarginLeft().getValueAsInt(rootBoxWidth);
}
private int rightMargin(@Nonnull final BoxConstraints boxConstraints, final int rootBoxWidth) {
return boxConstraints.getMarginRight().getValueAsInt(rootBoxWidth);
}
private int topMargin(@Nonnull final BoxConstraints boxConstraints, final int rootBoxHeight) {
return boxConstraints.getMarginTop().getValueAsInt(rootBoxHeight);
}
private int processHeightConstraint(
final int rootBoxHeight,
final Box box,
@Nonnull final BoxConstraints constraint,
final int elementWidth) {
if (hasHeightConstraint(constraint)) {
if (constraint.getHeight().hasWidthSuffix()) {
return constraint.getHeight().getValueAsInt(elementWidth);
}
return constraint.getHeight().getValueAsInt(rootBoxHeight);
} else {
return rootBoxHeight;
}
}
private boolean hasHeightConstraint(@Nullable final BoxConstraints constraint) {
return constraint != null && constraint.getHeight().hasValue();
}
private int calcElementWidth(
@Nonnull final List<LayoutPart> children,
final int rootBoxWidth,
@Nonnull final BoxConstraints boxConstraints,
final int elementHeight) {
if (boxConstraints.getWidth().hasValue()) {
int h = boxConstraints.getWidth().getValueAsInt(rootBoxWidth);
if (boxConstraints.getWidth().hasHeightSuffix()) {
h = boxConstraints.getWidth().getValueAsInt(elementHeight);
}
if (h != -1) {
return h;
}
}
return getMaxNonFixedWidth(children, rootBoxWidth);
}
private int processVerticalAlignment(
final int rootBoxY,
final int rootBoxHeight,
@Nonnull final Box box,
@Nonnull final BoxConstraints boxConstraints) {
if (VerticalAlign.center.equals(boxConstraints.getVerticalAlign())) {
return rootBoxY + ((rootBoxHeight - box.getHeight()) / 2);
} else if (VerticalAlign.top.equals(boxConstraints.getVerticalAlign())) {
return rootBoxY;
} else if (VerticalAlign.bottom.equals(boxConstraints.getVerticalAlign())) {
return rootBoxY + (rootBoxHeight - box.getHeight());
} else {
// top is default in here
return rootBoxY;
}
}
/**
* @param elements the child elements the max width is going
* to be calculated
* @param parentWidth the width of the parent element
* @return max non fixed width
*/
private int getMaxNonFixedWidth(
@Nonnull final List<LayoutPart> elements,
final int parentWidth
) {
int maxFixedWidth = 0;
int fixedCount = 0;
for (int i = 0; i < elements.size(); i++) {
LayoutPart p = elements.get(i);
BoxConstraints original = p.getBoxConstraints();
if (original.getWidth().hasValue()) {
maxFixedWidth += original.getWidth().getValueAsInt(parentWidth);
fixedCount++;
}
}
int notFixedCount = elements.size() - fixedCount;
if (notFixedCount > 0) {
return (parentWidth - maxFixedWidth) / notFixedCount;
} else {
return (parentWidth - maxFixedWidth);
}
}
/**
* @param children children elements of the root element
* @return new calculated SizeValue
*/
@Nonnull
@Override
public final SizeValue calculateConstraintWidth(
@Nonnull final LayoutPart root,
@Nonnull final List<LayoutPart> children) {
return root.getSumWidth(children);
}
/**
* @param children children elements of the root element
* @return new calculated SizeValue
*/
@Nonnull
@Override
public final SizeValue calculateConstraintHeight(
@Nonnull final LayoutPart root,
@Nonnull final List<LayoutPart> children) {
return root.getMaxHeight(children);
}
private boolean isInvalid(@Nullable final LayoutPart root, @Nullable final List<LayoutPart> children) {
return root == null || children == null || children.size() == 0;
}
private int getRootBoxX(@Nonnull final LayoutPart root) {
return root.getBox().getX() + root.getBoxConstraints().getPaddingLeft().getValueAsInt(root.getBox().getWidth());
}
private int getRootBoxY(@Nonnull final LayoutPart root) {
return root.getBox().getY() + root.getBoxConstraints().getPaddingTop().getValueAsInt(root.getBox().getHeight());
}
private int getRootBoxWidth(@Nonnull final LayoutPart root) {
return root.getBox().getWidth() - root.getBoxConstraints().getPaddingLeft().getValueAsInt(root.getBox().getWidth
()) - root.getBoxConstraints().getPaddingRight().getValueAsInt(root.getBox().getWidth());
}
private int getRootBoxHeight(@Nonnull final LayoutPart root) {
return root.getBox().getHeight() - root.getBoxConstraints().getPaddingTop().getValueAsInt(root.getBox().getHeight
()) - root.getBoxConstraints().getPaddingBottom().getValueAsInt(root.getBox().getHeight());
}
}