Package org.terasology.rendering.nui.layouts

Source Code of org.terasology.rendering.nui.layouts.MultiRowLayout$ColumnInfo

/*
* Copyright 2014 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.layouts;

import com.google.common.collect.Lists;
import com.google.gson.annotations.SerializedName;
import org.terasology.input.events.KeyEvent;
import org.terasology.input.events.MouseButtonEvent;
import org.terasology.input.events.MouseWheelEvent;
import org.terasology.math.Rect2i;
import org.terasology.math.TeraMath;
import org.terasology.math.Vector2i;
import org.terasology.rendering.nui.Canvas;
import org.terasology.rendering.nui.CoreLayout;
import org.terasology.rendering.nui.LayoutConfig;
import org.terasology.rendering.nui.LayoutHint;
import org.terasology.rendering.nui.UIWidget;

import java.util.Iterator;
import java.util.List;

/**
* @author Immortius
*/
public class MultiRowLayout extends CoreLayout<LayoutHint> {

    @LayoutConfig
    private int rows = 1;
    @LayoutConfig
    private int verticalSpacing;
    @LayoutConfig
    private int horizontalSpacing;
    @LayoutConfig
    private boolean autoSizeRows;

    private List<UIWidget> widgetList = Lists.newArrayList();

    @LayoutConfig
    @SerializedName("row-heights")
    private float[] rowHeights = new float[]{1.0f};

    public MultiRowLayout() {
    }

    public MultiRowLayout(String id) {
        super(id);
    }

    public void addWidget(UIWidget widget) {
        widgetList.add(widget);
    }

    public int getRows() {
        return rows;
    }

    public void setRows(int rows) {
        this.rows = rows;
        rowHeights = new float[rows];
        float equalHeight = 1.0f / rows;
        for (int i = 0; i < rowHeights.length; ++i) {
            rowHeights[i] = equalHeight;
        }
    }

    public void setRowHeights(float ... heights) {
        if (heights.length > rows) {
            throw new IllegalArgumentException("More heights than rows");
        }

        float total = 0;
        int rowIndex = 0;
        while (rowIndex < heights.length) {
            total += heights[rowIndex];
            rowHeights[rowIndex] = heights[rowIndex];
            rowIndex++;
        }

        if (total > 1.0f) {
            throw new IllegalArgumentException("Total height exceeds 1.0");
        }

        if (rowIndex < rowHeights.length) {
            float remainingHeight = 1.0f - total;
            float heightPerRow = remainingHeight / (rowHeights.length - rowIndex);
            while (rowIndex < rowHeights.length) {
                rowHeights[rowIndex++] = heightPerRow;
            }
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        if (!widgetList.isEmpty()) {
            Vector2i availableSize = canvas.size();
            int numColumns = TeraMath.ceilToInt((float) widgetList.size() / rows);
            if (numColumns > 0) {
                availableSize.x -= horizontalSpacing * (numColumns - 1);
            }
            if (rows > 0) {
                availableSize.y -= verticalSpacing * (rows - 1);
            }

            List<List<UIWidget>> columns = Lists.newArrayList(getColumnIterator());
            List<ColumnInfo> columnInfos = Lists.newArrayList();
            for (List<UIWidget> column : columns) {
                columnInfos.add(calculateColumnSize(column, canvas, availableSize));
            }

            int[] minHeights = new int[rows];
            int minColumnHeight = 0;
            int columnOffsetY = 0;
            if (autoSizeRows) {
                for (ColumnInfo column : columnInfos) {
                    for (int row = 0; row < column.widgetSizes.size(); row++) {
                        minHeights[row] = Math.max(minHeights[row], column.widgetSizes.get(row).getY());
                    }
                }

                for (int height : minHeights) {
                    minColumnHeight += height;
                }

                minColumnHeight += (rows - 1) * verticalSpacing;

                columnOffsetY = (canvas.size().y - minColumnHeight) / 2;
            } else {
                minColumnHeight = canvas.size().y;
                for (int i = 0; i < rows; ++i) {
                    minHeights[i] = TeraMath.floorToInt((minColumnHeight - (rows - 1) * verticalSpacing) * rowHeights[i]);
                }
            }

            int columnOffsetX = 0;
            int usedWidth = 0;
            for (ColumnInfo column : columnInfos) {
                usedWidth += column.width;
            }
            usedWidth += (columnInfos.size() - 1) * horizontalSpacing;
            columnOffsetX = (canvas.size().x - usedWidth) / 2;
            for (int columnIndex = 0; columnIndex < columns.size(); ++columnIndex) {
                List<UIWidget> column = columns.get(columnIndex);
                ColumnInfo columnInfo = columnInfos.get(columnIndex);
                int cellOffsetY = columnOffsetY;
                for (int i = 0; i < column.size(); ++i) {
                    UIWidget widget = column.get(i);
                    int columnWidth = columnInfo.width;
                    if (widget != null) {
                        Rect2i drawRegion = Rect2i.createFromMinAndSize(columnOffsetX, cellOffsetY, columnWidth, minHeights[i]);
                        canvas.drawWidget(widget, drawRegion);
                    }
                    cellOffsetY += minHeights[i] + verticalSpacing;
                }
                columnOffsetX += columnInfo.width + horizontalSpacing;
            }
        }
    }

    private ColumnInfo calculateColumnSize(List<UIWidget> column, Canvas canvas, Vector2i areaHint) {
        int availableHeight = areaHint.y - verticalSpacing * (rows - 1);

        ColumnInfo columnInfo = new ColumnInfo();

        for (int i = 0; i < rows && i < column.size(); ++i) {
            UIWidget widget = column.get(i);
            Vector2i cellSize = new Vector2i(areaHint.x, availableHeight);
            if (!autoSizeRows) {
                cellSize.y *= rowHeights[i];
            }
            if (widget != null) {
                Vector2i contentSize = canvas.calculateRestrictedSize(widget, cellSize);
                columnInfo.widgetSizes.add(contentSize);
                columnInfo.width = Math.max(columnInfo.width, contentSize.x);
            } else {
                columnInfo.widgetSizes.add(new Vector2i(0, 0));
            }
        }
        return columnInfo;
    }

    @Override
    public Vector2i getPreferredContentSize(Canvas canvas, Vector2i areaHint) {
        Vector2i availableSize = new Vector2i(areaHint);
        int numColumns = TeraMath.ceilToInt((float) widgetList.size() / rows);
        if (numColumns > 0) {
            availableSize.x -= horizontalSpacing * (numColumns - 1);
        }
        if (rows > 0) {
            availableSize.y -= verticalSpacing * (rows - 1);
        }

        Iterator<List<UIWidget>> columns = getColumnIterator();
        Vector2i size = new Vector2i();
        int[] rowSizes = new int[rows];
        while (columns.hasNext()) {
            List<UIWidget> column = columns.next();
            ColumnInfo columnInfo = calculateColumnSize(column, canvas, availableSize);
            size.x += columnInfo.width;
            if (columns.hasNext()) {
                size.x += horizontalSpacing;
            }
            for (int i = 0; i < columnInfo.widgetSizes.size(); ++i) {
                rowSizes[i] = Math.max(rowSizes[i], columnInfo.widgetSizes.get(i).getY());
            }
        }
        for (int rowSize : rowSizes) {
            size.y += rowSize;
        }

        if (!autoSizeRows) {
            for (int i = 0; i < rows; ++i) {
                size.y = Math.max(size.y, TeraMath.floorToInt(rowSizes[i] / rowHeights[i]));
            }
        }

        size.y += verticalSpacing * (rows - 1);

        return size;
    }

    @Override
    public Vector2i getMaxContentSize(Canvas canvas) {
        Iterator<List<UIWidget>> columns = getColumnIterator();
        Vector2i size = new Vector2i();
        int[] rowSizes = new int[rows];
        while (columns.hasNext()) {
            List<UIWidget> column = columns.next();
            int columnWidth = 0;
            for (int i = 0; i < column.size(); ++i) {
                Vector2i maxSize = canvas.calculateMaximumSize(column.get(i));
                rowSizes[i] = Math.max(rowSizes[i], maxSize.y);
                columnWidth = Math.max(columnWidth, maxSize.x);
            }
            size.x = TeraMath.addClampAtMax(size.x, columnWidth);
            if (columns.hasNext()) {
                size.x = TeraMath.addClampAtMax(size.x, horizontalSpacing);
            }
        }

        long height = 0;
        for (int rowSize : rowSizes) {
            height += rowSize;
        }

        if (!autoSizeRows) {
            for (int i = 0; i < rows; ++i) {
                height = Math.min(height, TeraMath.floorToInt(rowSizes[i] / rowHeights[i]));
            }
        }

        height += verticalSpacing * (rows - 1);

        size.y = (int) Math.min(Integer.MAX_VALUE, height);
        return size;
    }

    @Override
    public void update(float delta) {
        for (UIWidget widget : widgetList) {
            widget.update(delta);
        }
    }

    @Override
    public void onMouseButtonEvent(MouseButtonEvent event) {
    }

    @Override
    public void onMouseWheelEvent(MouseWheelEvent event) {
    }

    @Override
    public void onKeyEvent(KeyEvent event) {
    }

    @Override
    public Iterator<UIWidget> iterator() {
        return widgetList.iterator();
    }

    @Override
    public void addWidget(UIWidget element, LayoutHint hint) {
        addWidget(element);
    }

    public int getHorizontalSpacing() {
        return horizontalSpacing;
    }

    public void setHorizontalSpacing(int horizontalSpacing) {
        this.horizontalSpacing = horizontalSpacing;
    }

    public int getVerticalSpacing() {
        return verticalSpacing;
    }

    public void setVerticalSpacing(int verticalSpacing) {
        this.verticalSpacing = verticalSpacing;
    }

    public boolean isAutoSizeRows() {
        return autoSizeRows;
    }

    public void setAutoSizeRows(boolean autoSizeRows) {
        this.autoSizeRows = autoSizeRows;
    }

    private Iterator<List<UIWidget>> getColumnIterator() {
        return new Iterator<List<UIWidget>>() {

            Iterator<UIWidget> contentIterator = iterator();

            @Override
            public boolean hasNext() {
                return contentIterator.hasNext();
            }

            @Override
            public List<UIWidget> next() {
                List<UIWidget> column = Lists.newArrayList();
                for (int i = 0; i < rows; ++i) {
                    if (contentIterator.hasNext()) {
                        column.add(contentIterator.next());
                    }
                }
                return column;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }

    private static class ColumnInfo {
        private int width;
        private List<Vector2i> widgetSizes = Lists.newArrayList();

        @Override
        public String toString() {
            return super.toString() + "{width:" + width + ", widgetSizes:" + widgetSizes + "}";
        }
    }
}
TOP

Related Classes of org.terasology.rendering.nui.layouts.MultiRowLayout$ColumnInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.