/*
* 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.math.geom.Vector2i;
import org.terasology.rendering.assets.font.Font;
import org.terasology.rendering.nui.Canvas;
import org.terasology.rendering.nui.Color;
import org.terasology.rendering.nui.widgets.browser.data.DocumentData;
import org.terasology.rendering.nui.widgets.browser.data.ParagraphData;
import org.terasology.rendering.nui.widgets.browser.data.basic.flow.ContainerRenderSpace;
import org.terasology.rendering.nui.widgets.browser.ui.style.DefaultDocumentRenderStyle;
import org.terasology.rendering.nui.widgets.browser.ui.style.DocumentRenderStyle;
import org.terasology.rendering.nui.widgets.browser.ui.style.FallbackDocumentRenderStyle;
import org.terasology.rendering.nui.widgets.browser.ui.style.FallbackParagraphRenderStyle;
import org.terasology.rendering.nui.widgets.browser.ui.style.ParagraphRenderStyle;
import java.util.Collection;
public final class DocumentRenderer {
private DocumentRenderer() {
}
public static Vector2i getDocumentPreferredSize(DocumentData documentData, Font defaultFont, Color defaultColor, int availableWidth) {
DefaultDocumentRenderStyle defaultDocumentRenderStyle = new DefaultDocumentRenderStyle(defaultFont, defaultColor);
DocumentRenderStyle documentRenderStyle = getDocumentRenderStyle(defaultDocumentRenderStyle, documentData);
Collection<ParagraphData> paragraphs = documentData.getParagraphs();
int minParagraphsWidth = getParagraphsMinimumWidth(availableWidth, documentRenderStyle, paragraphs);
int documentSideMargins = documentRenderStyle.getDocumentMarginLeft().getValue(availableWidth)
+ documentRenderStyle.getDocumentMarginRight().getValue(availableWidth);
int documentWidth = Math.max(availableWidth, minParagraphsWidth + documentSideMargins);
ContainerFlowContainerRenderSpace containerRenderSpace = new ContainerFlowContainerRenderSpace(documentWidth);
int preferredHeight = Math.max(
getParagraphsPreferredHeight(documentRenderStyle, paragraphs, containerRenderSpace, 0),
containerRenderSpace.getNextClearYPosition(ParagraphRenderStyle.ClearStyle.BOTH));
int documentVerticalMargins = documentRenderStyle.getDocumentMarginTop().getValue(documentWidth)
+ documentRenderStyle.getDocumentMarginBottom().getValue(documentWidth);
// Bring back the document indents to sides
return new Vector2i(documentWidth, preferredHeight + documentVerticalMargins);
}
public static int getParagraphsMinimumWidth(int availableWidth, ParagraphRenderStyle baseParagraphRenderStyle, Collection<ParagraphData> paragraphs) {
int minParagraphsWidth = 0;
for (ParagraphData paragraphData : paragraphs) {
ParagraphRenderStyle paragraphRenderStyle = getParagraphRenderStyle(baseParagraphRenderStyle, paragraphData);
int paragraphSideIndent = paragraphRenderStyle.getParagraphMarginLeft().getValue(availableWidth)
+ paragraphRenderStyle.getParagraphMarginRight().getValue(availableWidth)
+ paragraphRenderStyle.getParagraphPaddingLeft().getValue(availableWidth)
+ paragraphRenderStyle.getParagraphPaddingRight().getValue(availableWidth);
int paragraphMinWidth = Math.max(paragraphRenderStyle.getParagraphMinimumWidth().getValue(availableWidth),
paragraphData.getParagraphContents().getContentsMinWidth(paragraphRenderStyle));
minParagraphsWidth = Math.max(minParagraphsWidth, paragraphSideIndent + paragraphMinWidth);
}
return minParagraphsWidth;
}
public static int getParagraphsPreferredHeight(ParagraphRenderStyle baseRenderStyle, Collection<ParagraphData> paragraphs,
ContainerRenderSpace containerRenderSpace, int yStart) {
int containerWidth = containerRenderSpace.getContainerWidth();
int yShift = yStart;
for (ParagraphData paragraphData : paragraphs) {
ParagraphRenderStyle paragraphRenderStyle = getParagraphRenderStyle(baseRenderStyle, paragraphData);
ParagraphRenderStyle.ClearStyle clearStyle = paragraphRenderStyle.getClearStyle();
if (clearStyle != ParagraphRenderStyle.ClearStyle.NONE) {
yShift = Math.max(yShift, containerRenderSpace.getNextClearYPosition(clearStyle));
}
ParagraphRenderStyle.FloatStyle floatStyle = paragraphRenderStyle.getFloatStyle();
if (floatStyle == ParagraphRenderStyle.FloatStyle.LEFT
|| floatStyle == ParagraphRenderStyle.FloatStyle.RIGHT) {
int paragraphMinWidth = Math.max(paragraphRenderStyle.getParagraphMinimumWidth().getValue(containerWidth),
paragraphData.getParagraphContents().getContentsMinWidth(paragraphRenderStyle));
int paragraphSideIndent = paragraphRenderStyle.getParagraphMarginLeft().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphMarginRight().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingLeft().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingRight().getValue(containerWidth);
int height = paragraphRenderStyle.getParagraphMarginTop().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingTop().getValue(containerWidth);
height += paragraphData.getParagraphContents().getPreferredContentsHeight(paragraphRenderStyle, 0,
new ContainerFlowContainerRenderSpace(paragraphMinWidth), paragraphSideIndent);
height += paragraphRenderStyle.getParagraphPaddingBottom().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphMarginBottom().getValue(containerWidth);
if (floatStyle == ParagraphRenderStyle.FloatStyle.LEFT) {
Rect2i position = containerRenderSpace.addLeftFloat(yShift, paragraphMinWidth, height);
yShift = position.minY();
} else {
Rect2i position = containerRenderSpace.addRightFloat(yShift, paragraphMinWidth, height);
yShift = position.minY();
}
} else {
yShift += paragraphRenderStyle.getParagraphMarginTop().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingTop().getValue(containerWidth);
int paragraphSideIndent = paragraphRenderStyle.getParagraphMarginLeft().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphMarginRight().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingLeft().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingRight().getValue(containerWidth);
yShift += paragraphData.getParagraphContents().getPreferredContentsHeight(paragraphRenderStyle, yShift, containerRenderSpace, paragraphSideIndent);
yShift += paragraphRenderStyle.getParagraphPaddingBottom().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphMarginBottom().getValue(containerWidth);
}
}
return yShift - yStart;
}
public static void drawDocumentInRegion(DocumentData documentData, Canvas canvas, Font defaultFont, Color defaultColor,
Vector2i size, ParagraphRenderable.HyperlinkRegister register) {
DefaultDocumentRenderStyle defaultDocumentRenderStyle = new DefaultDocumentRenderStyle(defaultFont, defaultColor);
DocumentRenderStyle documentRenderStyle = getDocumentRenderStyle(defaultDocumentRenderStyle, documentData);
int documentWidth = size.x;
int documentMarginLeft = documentRenderStyle.getDocumentMarginLeft().getValue(documentWidth);
int documentMarginRight = documentRenderStyle.getDocumentMarginRight().getValue(documentWidth);
int documentMarginTop = documentRenderStyle.getDocumentMarginTop().getValue(documentWidth);
Color backgroundColor = documentRenderStyle.getBackgroundColor();
if (backgroundColor != null) {
canvas.drawFilledRectangle(canvas.getRegion(), backgroundColor);
}
Collection<ParagraphData> paragraphs = documentData.getParagraphs();
ContainerFlowContainerRenderSpace renderSpace = new ContainerFlowContainerRenderSpace(documentWidth);
renderParagraphs(canvas, register, documentRenderStyle, documentMarginLeft, documentMarginTop, documentMarginLeft, documentMarginRight, paragraphs, renderSpace);
}
public static void renderParagraphs(Canvas canvas, ParagraphRenderable.HyperlinkRegister register, ParagraphRenderStyle baseRenderStyle,
int xShift, int startY, int leftIndent, int rightIndent, Collection<ParagraphData> paragraphs,
ContainerRenderSpace containerRenderSpace) {
int containerWidth = containerRenderSpace.getContainerWidth();
int yShift = startY;
for (ParagraphData paragraphData : paragraphs) {
yShift += renderParagraph(canvas, register, baseRenderStyle, xShift, leftIndent, rightIndent, containerRenderSpace,
containerWidth, yShift, paragraphData);
}
}
public static int renderParagraph(Canvas canvas, ParagraphRenderable.HyperlinkRegister register, ParagraphRenderStyle baseRenderStyle,
int xShift, int leftIndent, int rightIndent, ContainerRenderSpace containerRenderSpace, int containerWidth,
int startY, ParagraphData paragraphData) {
int yShift = startY;
ParagraphRenderable paragraphContents = paragraphData.getParagraphContents();
ParagraphRenderStyle paragraphRenderStyle = getParagraphRenderStyle(baseRenderStyle, paragraphData);
ParagraphRenderStyle.ClearStyle clearStyle = paragraphRenderStyle.getClearStyle();
if (clearStyle != ParagraphRenderStyle.ClearStyle.NONE) {
yShift = Math.max(yShift, containerRenderSpace.getNextClearYPosition(clearStyle));
}
ParagraphRenderStyle.FloatStyle floatStyle = paragraphRenderStyle.getFloatStyle();
if (floatStyle == ParagraphRenderStyle.FloatStyle.LEFT
|| floatStyle == ParagraphRenderStyle.FloatStyle.RIGHT) {
int leftParagraphIndent = paragraphRenderStyle.getParagraphMarginLeft().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingLeft().getValue(containerWidth);
int rightParagraphIndent = paragraphRenderStyle.getParagraphMarginRight().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingRight().getValue(containerWidth);
int paragraphWidth = Math.max(paragraphRenderStyle.getParagraphMinimumWidth().getValue(containerWidth),
paragraphContents.getContentsMinWidth(paragraphRenderStyle) + leftParagraphIndent + rightParagraphIndent);
int height = paragraphRenderStyle.getParagraphMarginTop().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingTop().getValue(containerWidth);
int paragraphHeight = paragraphContents.getPreferredContentsHeight(paragraphRenderStyle, 0,
new ContainerFlowContainerRenderSpace(paragraphWidth), leftParagraphIndent + rightParagraphIndent);
height += paragraphHeight;
height += paragraphRenderStyle.getParagraphPaddingBottom().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphMarginBottom().getValue(containerWidth);
Rect2i position;
if (floatStyle == ParagraphRenderStyle.FloatStyle.LEFT) {
position = containerRenderSpace.addLeftFloat(yShift, paragraphWidth, height);
} else {
position = containerRenderSpace.addRightFloat(yShift, paragraphWidth, height);
}
Rect2i paragraphBorderRegion =
Rect2i.createFromMinAndMax(position.minX() + paragraphRenderStyle.getParagraphMarginLeft().getValue(containerWidth),
position.minY() + paragraphRenderStyle.getParagraphMarginTop().getValue(containerWidth),
position.maxX() - paragraphRenderStyle.getParagraphMarginRight().getValue(containerWidth) - 1,
position.maxY() - paragraphRenderStyle.getParagraphMarginBottom().getValue(containerWidth) - 1);
Color paragraphBackground = paragraphRenderStyle.getParagraphBackground();
if (paragraphBackground != null) {
canvas.drawFilledRectangle(paragraphBorderRegion, paragraphBackground);
}
Vector2i paragraphStart = new Vector2i(position.minX(),
position.minY()
+ paragraphRenderStyle.getParagraphMarginTop().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingTop().getValue(containerWidth));
paragraphContents.renderContents(canvas, paragraphStart, new ContainerFlowContainerRenderSpace(paragraphWidth),
leftParagraphIndent, rightParagraphIndent, paragraphRenderStyle, paragraphRenderStyle.getHorizontalAlignment(), register);
yShift = position.minY();
} else {
yShift += paragraphRenderStyle.getParagraphMarginTop().getValue(containerWidth);
int leftParagraphIndent = paragraphRenderStyle.getParagraphMarginLeft().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingLeft().getValue(containerWidth);
int rightParagraphIndent = paragraphRenderStyle.getParagraphMarginRight().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingRight().getValue(containerWidth);
int paragraphHeight = paragraphContents.getPreferredContentsHeight(paragraphRenderStyle,
yShift + paragraphRenderStyle.getParagraphPaddingTop().getValue(containerWidth), containerRenderSpace,
leftIndent + leftParagraphIndent + rightParagraphIndent + rightIndent);
Color paragraphBackground = paragraphRenderStyle.getParagraphBackground();
if (paragraphBackground != null) {
int borderAdvance = 0;
int borderHeight = paragraphHeight + paragraphRenderStyle.getParagraphPaddingTop().getValue(containerWidth)
+ paragraphRenderStyle.getParagraphPaddingBottom().getValue(containerWidth);
while (borderAdvance < borderHeight) {
int backgroundStart = yShift + borderAdvance;
int availableBackgroundWidth = containerRenderSpace.getWidthForVerticalPosition(backgroundStart);
int backgroundAdvance = containerRenderSpace.getAdvanceForVerticalPosition(backgroundStart);
int maxSpace = containerRenderSpace.getNextWidthChange(backgroundStart);
Rect2i backgroundRegion =
Rect2i.createFromMinAndSize(
xShift + paragraphRenderStyle.getParagraphMarginLeft().getValue(containerWidth) + backgroundAdvance,
backgroundStart,
availableBackgroundWidth - 1,
Math.min(maxSpace, borderHeight - borderAdvance) - 1);
canvas.drawFilledRectangle(backgroundRegion, paragraphBackground);
borderAdvance += maxSpace - backgroundStart;
}
}
yShift += paragraphRenderStyle.getParagraphPaddingTop().getValue(containerWidth);
paragraphContents.renderContents(canvas, new Vector2i(xShift, yShift), containerRenderSpace, leftIndent + leftParagraphIndent,
rightIndent + rightParagraphIndent, paragraphRenderStyle, paragraphRenderStyle.getHorizontalAlignment(), register);
yShift += paragraphHeight;
yShift += paragraphRenderStyle.getParagraphPaddingBottom().getValue(containerWidth);
yShift += paragraphRenderStyle.getParagraphMarginBottom().getValue(containerWidth);
}
return yShift - startY;
}
private static DocumentRenderStyle getDocumentRenderStyle(DefaultDocumentRenderStyle defaultDocumentRenderStyle, DocumentData document) {
DocumentRenderStyle documentStyle = document.getDocumentRenderStyle();
if (documentStyle == null) {
return defaultDocumentRenderStyle;
}
return new FallbackDocumentRenderStyle(documentStyle, defaultDocumentRenderStyle);
}
private static ParagraphRenderStyle getParagraphRenderStyle(ParagraphRenderStyle documentRenderStyle, ParagraphData paragraphData) {
ParagraphRenderStyle paragraphStyle = paragraphData.getParagraphRenderStyle();
if (paragraphStyle == null) {
return documentRenderStyle;
}
return new FallbackParagraphRenderStyle(paragraphStyle, documentRenderStyle);
}
}