Package org.terasology.rendering.nui.layouts

Source Code of org.terasology.rendering.nui.layouts.ColumnLayout$RowInfo

/*
* 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 ColumnLayout extends CoreLayout<LayoutHint> {

    @LayoutConfig
    private int columns = 1;
    @LayoutConfig
    private int horizontalSpacing;
    @LayoutConfig
    private int verticalSpacing;
    @LayoutConfig
    private boolean autoSizeColumns;
    @LayoutConfig
    private boolean fillVerticalSpace = true;

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

    @LayoutConfig
    @SerializedName("column-widths")
    private float[] columnWidths = new float[]{1.0f};

    public ColumnLayout() {
    }

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

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

    public int getColumns() {
        return columns;
    }

    public void setColumns(int columns) {
        this.columns = columns;
        columnWidths = new float[columns];
        float equalWidth = 1.0f / columns;
        for (int i = 0; i < columnWidths.length; ++i) {
            columnWidths[i] = equalWidth;
        }
    }

    public void setColumnWidths(float... widths) {
        if (widths.length > columns) {
            throw new IllegalArgumentException("More widths than columns");
        }

        float total = 0;
        int columnIndex = 0;
        while (columnIndex < widths.length) {
            total += widths[columnIndex];
            columnWidths[columnIndex] = widths[columnIndex];
            columnIndex++;
        }

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

        if (columnIndex < columnWidths.length) {
            float remainingWidth = 1.0f - total;
            float widthPerColumn = remainingWidth / (columnWidths.length - columnIndex);
            while (columnIndex < columnWidths.length) {
                columnWidths[columnIndex++] = widthPerColumn;
            }
        }
    }

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

            List<List<UIWidget>> rows = Lists.newArrayList(getRowIterator());
            List<RowInfo> rowInfos = Lists.newArrayList();
            for (List<UIWidget> row : rows) {
                rowInfos.add(calculateRowSize(row, canvas, availableSize));
            }

            int[] minWidths = new int[columns];
            int minRowWidth = 0;
            int rowOffsetX = 0;
            if (autoSizeColumns) {
                for (RowInfo row : rowInfos) {
                    for (int column = 0; column < row.widgetSizes.size(); column++) {
                        minWidths[column] = Math.max(minWidths[column], row.widgetSizes.get(column).getX());
                    }
                }

                for (int width : minWidths) {
                    minRowWidth += width;
                }

                minRowWidth += (columns - 1) * horizontalSpacing;

                rowOffsetX = (canvas.size().x - minRowWidth) / 2;
            } else {
                minRowWidth = canvas.size().x;
                for (int i = 0; i < columns; ++i) {
                    minWidths[i] = TeraMath.floorToInt((minRowWidth - (columns - 1) * horizontalSpacing) * columnWidths[i]);
                }
            }

            int rowOffsetY = 0;
            int usedHeight = 0;
            for (RowInfo row : rowInfos) {
                usedHeight += row.height;
            }
            usedHeight += (rowInfos.size() - 1) * verticalSpacing;

            if (fillVerticalSpace) {
                int extraSpacePerRow = (canvas.size().y - usedHeight) / rowInfos.size();

                for (RowInfo row : rowInfos) {
                    row.height += extraSpacePerRow;
                }
            } else {
                rowOffsetY = (canvas.size().y - usedHeight) / 2;
            }
            for (int rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
                List<UIWidget> row = rows.get(rowIndex);
                RowInfo rowInfo = rowInfos.get(rowIndex);
                int cellOffsetX = rowOffsetX;
                for (int i = 0; i < row.size(); ++i) {
                    UIWidget widget = row.get(i);
                    int rowHeight = rowInfo.height;
                    if (widget != null) {
                        Rect2i drawRegion = Rect2i.createFromMinAndSize(cellOffsetX, rowOffsetY, minWidths[i], rowHeight);
                        canvas.drawWidget(widget, drawRegion);
                    }
                    cellOffsetX += minWidths[i] + horizontalSpacing;
                }
                rowOffsetY += rowInfo.height + verticalSpacing;
            }
        }
    }

    private RowInfo calculateRowSize(List<UIWidget> row, Canvas canvas, Vector2i areaHint) {
        int availableWidth = areaHint.x - horizontalSpacing * (columns - 1);

        RowInfo rowInfo = new RowInfo();

        for (int i = 0; i < columns && i < row.size(); ++i) {
            UIWidget widget = row.get(i);
            Vector2i cellSize = new Vector2i(availableWidth, areaHint.y);
            if (!autoSizeColumns) {
                cellSize.x *= columnWidths[i];
            }
            if (widget != null) {
                Vector2i contentSize = canvas.calculateRestrictedSize(widget, cellSize);
                rowInfo.widgetSizes.add(contentSize);
                rowInfo.height = Math.max(rowInfo.height, contentSize.y);
            } else {
                rowInfo.widgetSizes.add(new Vector2i(0, 0));
            }
        }
        return rowInfo;
    }

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

        Iterator<List<UIWidget>> rows = getRowIterator();
        Vector2i size = new Vector2i();
        int[] columnSizes = new int[columns];
        while (rows.hasNext()) {
            List<UIWidget> row = rows.next();
            RowInfo rowInfo = calculateRowSize(row, canvas, availableSize);
            size.y += rowInfo.height;
            if (rows.hasNext()) {
                size.y += verticalSpacing;
            }
            for (int i = 0; i < rowInfo.widgetSizes.size(); ++i) {
                columnSizes[i] = Math.max(columnSizes[i], rowInfo.widgetSizes.get(i).getX());
            }
        }
        for (int columnSize : columnSizes) {
            size.x += columnSize;
        }

        if (!autoSizeColumns) {
            for (int i = 0; i < columns; ++i) {
                size.x = Math.max(size.x, TeraMath.floorToInt(columnSizes[i] / columnWidths[i]));
            }
        }

        size.x += horizontalSpacing * (columns - 1);

        return size;
    }

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

        long width = 0;
        for (int columnSize : columnSizes) {
            width += columnSize;
        }

        if (!autoSizeColumns) {
            for (int i = 0; i < columns; ++i) {
                width = Math.min(width, TeraMath.floorToInt(columnSizes[i] / columnWidths[i]));
            }
        }

        width += horizontalSpacing * (columns - 1);

        size.x = (int) Math.min(Integer.MAX_VALUE, width);
        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 isAutoSizeColumns() {
        return autoSizeColumns;
    }

    public void setAutoSizeColumns(boolean autoSizeColumns) {
        this.autoSizeColumns = autoSizeColumns;
    }

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

            Iterator<UIWidget> contentIterator = iterator();

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

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

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

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

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

Related Classes of org.terasology.rendering.nui.layouts.ColumnLayout$RowInfo

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.