/*
* Copyright 2015 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.rendering.nui.widgets.browser.ui;
import org.terasology.math.geom.Rect2i;
import org.terasology.rendering.nui.widgets.browser.data.basic.flow.ContainerRenderSpace;
import org.terasology.rendering.nui.widgets.browser.ui.style.ParagraphRenderStyle;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
public class ContainerFlowContainerRenderSpace implements ContainerRenderSpace {
private Deque<Rect2i> leftFloats = new LinkedList<>();
private Deque<Rect2i> rightFloats = new LinkedList<>();
private int containerWidth;
public ContainerFlowContainerRenderSpace(int containerWidth) {
this.containerWidth = containerWidth;
}
@Override
public int getContainerWidth() {
return containerWidth;
}
@Override
public int getNextWidthChange(int y) {
Rect2i lastLeftFloat = findLastAtYPosition(leftFloats, y);
Rect2i lastRightFloat = findLastAtYPosition(rightFloats, y);
if (lastLeftFloat != null && lastRightFloat != null) {
return Math.min(lastLeftFloat.maxY(), lastRightFloat.maxY());
} else if (lastLeftFloat != null) {
return lastLeftFloat.maxY();
} else if (lastRightFloat != null) {
return lastRightFloat.maxY();
} else {
return Integer.MAX_VALUE;
}
}
@Override
public Rect2i addLeftFloat(int y, int width, int height) {
int posY = y;
while (true) {
int availableWidth = getAvailableWidthAt(posY);
if (availableWidth >= width) {
int x = 0;
Rect2i lastLeft = findLastAtYPosition(leftFloats, posY);
if (lastLeft != null) {
x = lastLeft.maxX();
}
Rect2i floatRect = Rect2i.createFromMinAndSize(x, posY, width, height);
leftFloats.add(floatRect);
return floatRect;
} else {
Rect2i lastLeft = findLastAtYPosition(leftFloats, posY);
Rect2i lastRight = findLastAtYPosition(rightFloats, posY);
if (lastLeft != null && lastRight != null) {
posY = Math.min(lastLeft.maxY(), lastRight.maxY());
} else if (lastLeft != null) {
posY = lastLeft.maxY();
} else if (lastRight != null) {
posY = lastRight.maxY();
}
}
}
}
@Override
public Rect2i addRightFloat(int y, int width, int height) {
int posY = y;
while (true) {
int availableWidth = getAvailableWidthAt(posY);
if (availableWidth >= width) {
int x = 0;
Rect2i lastRight = findLastAtYPosition(rightFloats, posY);
if (lastRight != null) {
x = lastRight.minX();
}
Rect2i floatRect = Rect2i.createFromMinAndSize(x - width, posY, width, height);
rightFloats.add(floatRect);
return floatRect;
} else {
Rect2i lastLeft = findLastAtYPosition(leftFloats, posY);
Rect2i lastRight = findLastAtYPosition(rightFloats, posY);
if (lastLeft != null && lastRight != null) {
posY = Math.min(lastLeft.maxY(), lastRight.maxY());
} else if (lastLeft != null) {
posY = lastLeft.maxY();
} else if (lastRight != null) {
posY = lastRight.maxY();
}
}
}
}
@Override
public int getNextClearYPosition(ParagraphRenderStyle.ClearStyle clearStyle) {
int maxY = 0;
if (clearStyle == ParagraphRenderStyle.ClearStyle.LEFT
|| clearStyle == ParagraphRenderStyle.ClearStyle.BOTH) {
for (Rect2i leftFloat : leftFloats) {
maxY = Math.max(maxY, leftFloat.maxY());
}
}
if (clearStyle == ParagraphRenderStyle.ClearStyle.RIGHT
|| clearStyle == ParagraphRenderStyle.ClearStyle.BOTH) {
for (Rect2i rightFloat : rightFloats) {
maxY = Math.max(maxY, rightFloat.maxY());
}
}
return maxY;
}
@Override
public int getWidthForVerticalPosition(int y) {
return getAvailableWidthAt(y);
}
@Override
public int getAdvanceForVerticalPosition(int y) {
Rect2i lastLeft = findLastAtYPosition(leftFloats, y);
if (lastLeft != null) {
return lastLeft.maxX();
} else {
return 0;
}
}
private int getAvailableWidthAt(int y) {
int width = containerWidth;
Rect2i lastRight = findLastAtYPosition(rightFloats, y);
if (lastRight != null) {
width = lastRight.minX();
}
Rect2i lastLeft = findLastAtYPosition(leftFloats, y);
if (lastLeft != null) {
width -= lastLeft.maxX();
}
return width;
}
private Rect2i findLastAtYPosition(Deque<Rect2i> floats, int y) {
Iterator<Rect2i> iterator = floats.descendingIterator();
while (iterator.hasNext()) {
Rect2i rect = iterator.next();
if (rect.minY() <= y && rect.maxY() > y) {
return rect;
}
}
return null;
}
}