/*
* 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.data.basic.flow;
import org.terasology.rendering.nui.widgets.browser.ui.style.TextRenderStyle;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
public final class FlowLineBuilder {
private FlowLineBuilder() {
}
public static <T extends FlowRenderable<T>> Iterable<LaidFlowLine<T>> getLines(Collection<T> flowRenderables, TextRenderStyle defaultRenderStyle,
int yStart, ContainerRenderSpace containerRenderSpace) {
// Take into account a minimum width
int minWidth = determineMinWidth(flowRenderables, defaultRenderStyle);
int x = 0;
int y = yStart;
int availableWidth = Math.max(minWidth, containerRenderSpace.getWidthForVerticalPosition(y));
List<LaidFlowLine<T>> result = new LinkedList<>();
int maxHeightInLine = 0;
Deque<T> renderablesQueue = new LinkedList<>(flowRenderables);
List<T> renderablesInLine = new LinkedList<>();
while (!renderablesQueue.isEmpty()) {
FlowRenderable<T> flowRenderable = renderablesQueue.removeFirst();
FlowRenderable.SplitResult<T> splitResult = flowRenderable.splitAt(defaultRenderStyle, availableWidth - x);
if (splitResult.before == null) {
// This is the end of the line, this renderable doesn't fit
result.add(new DefaultLaidFlowLine<>(x, maxHeightInLine, renderablesInLine));
renderablesInLine = new LinkedList<>();
x = 0;
y += maxHeightInLine;
availableWidth = Math.max(minWidth, containerRenderSpace.getWidthForVerticalPosition(y));
maxHeightInLine = 0;
renderablesQueue.addFirst(splitResult.rest);
} else {
// Append the "before" part and push the "rest" onto the Deque if not null
int renderableWidth = splitResult.before.getWidth(defaultRenderStyle);
int renderableHeight = splitResult.before.getHeight(defaultRenderStyle);
x += renderableWidth;
maxHeightInLine = Math.max(maxHeightInLine, renderableHeight);
renderablesInLine.add(splitResult.before);
if (splitResult.rest != null) {
result.add(new DefaultLaidFlowLine<>(x, maxHeightInLine, renderablesInLine));
renderablesInLine = new LinkedList<>();
x = 0;
y += maxHeightInLine;
availableWidth = Math.max(minWidth, containerRenderSpace.getWidthForVerticalPosition(y));
maxHeightInLine = 0;
renderablesQueue.addFirst(splitResult.rest);
}
}
}
result.add(new DefaultLaidFlowLine<>(x, maxHeightInLine, renderablesInLine));
return result;
}
private static <T extends FlowRenderable> int determineMinWidth(Iterable<T> flowRenderables, TextRenderStyle defaultRenderStyle) {
int minWidth = 0;
for (FlowRenderable flowRenderable : flowRenderables) {
minWidth = Math.max(minWidth, flowRenderable.getMinWidth(defaultRenderStyle));
}
return minWidth;
}
}