de.johni0702.minecraft.gui.layout.GridLayout.java Source code

Java tutorial

Introduction

Here is the source code for de.johni0702.minecraft.gui.layout.GridLayout.java

Source

/*
 * This file is part of jGui API, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2016 johni0702 <https://github.com/johni0702>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package de.johni0702.minecraft.gui.layout;

import com.google.common.base.Preconditions;
import de.johni0702.minecraft.gui.container.GuiContainer;
import de.johni0702.minecraft.gui.element.GuiElement;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.util.Dimension;
import org.lwjgl.util.Point;
import org.lwjgl.util.ReadableDimension;
import org.lwjgl.util.ReadablePoint;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

public class GridLayout implements Layout {
    private static final Data DEFAULT_DATA = new Data();

    @Accessors(chain = true)
    @Getter
    @Setter
    private int columns;

    @Accessors(chain = true)
    @Getter
    @Setter
    private int spacingX, spacingY;

    @Accessors(chain = true)
    @Getter
    @Setter
    private boolean cellsEqualSize = true;

    @Override
    public Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> layOut(GuiContainer<?> container,
            ReadableDimension size) {
        Preconditions.checkState(columns != 0, "Columns may not be 0.");
        int elements = container.getElements().size();
        int rows = (elements - 1 + columns) / columns;
        if (rows < 1) {
            return Collections.emptyMap();
        }
        int cellWidth = (size.getWidth() + spacingX) / columns - spacingX;
        int cellHeight = (size.getHeight() + spacingY) / rows - spacingY;

        Pair<int[], int[]> maxCellSize = null;

        if (!cellsEqualSize) {
            maxCellSize = calcNeededCellSize(container);
        }

        Map<GuiElement, Pair<ReadablePoint, ReadableDimension>> map = new LinkedHashMap<>();
        Iterator<Map.Entry<GuiElement, LayoutData>> iter = container.getElements().entrySet().iterator();
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                if (!iter.hasNext()) {
                    return map;
                }
                int x = j * (cellWidth + spacingX);
                int y = i * (cellHeight + spacingY);

                if (maxCellSize != null) {
                    cellWidth = maxCellSize.getLeft()[j];
                    cellHeight = maxCellSize.getRight()[i];

                    x = 0;
                    for (int x1 = 0; x1 < j; x1++) {
                        x += maxCellSize.getLeft()[x1];
                        x += spacingX;
                    }

                    y = 0;
                    for (int y1 = 0; y1 < i; y1++) {
                        y += maxCellSize.getRight()[y1];
                        y += spacingY;
                    }
                }

                Map.Entry<GuiElement, LayoutData> entry = iter.next();
                GuiElement element = entry.getKey();
                Data data = entry.getValue() instanceof Data ? (Data) entry.getValue() : DEFAULT_DATA;
                Dimension elementSize = new Dimension(element.getMinSize());
                ReadableDimension elementMaxSize = element.getMaxSize();
                elementSize.setWidth(Math.min(cellWidth, elementMaxSize.getWidth()));
                elementSize.setHeight(Math.min(cellHeight, elementMaxSize.getHeight()));

                int remainingWidth = cellWidth - elementSize.getWidth();
                int remainingHeight = cellHeight - elementSize.getHeight();
                x += (int) (data.alignmentX * remainingWidth);
                y += (int) (data.alignmentY * remainingHeight);
                map.put(element, Pair.<ReadablePoint, ReadableDimension>of(new Point(x, y), elementSize));
            }
        }
        return map;
    }

    @Override
    public ReadableDimension calcMinSize(GuiContainer<?> container) {
        Preconditions.checkState(columns != 0, "Columns may not be 0.");
        int maxWidth = 0, maxHeight = 0;

        int elements = 0;
        for (Map.Entry<GuiElement, LayoutData> entry : container.getElements().entrySet()) {
            GuiElement element = entry.getKey();
            ReadableDimension minSize = element.getMinSize();

            int width = minSize.getWidth();
            if (width > maxWidth) {
                maxWidth = width;
            }

            int height = minSize.getHeight();
            if (height > maxHeight) {
                maxHeight = height;
            }
            elements++;
        }
        int rows = (elements - 1 + columns) / columns;

        int totalWidth = maxWidth * columns;
        int totalHeight = maxHeight * rows;

        if (!cellsEqualSize) {
            Pair<int[], int[]> maxCellSize = calcNeededCellSize(container);

            totalWidth = 0;
            for (int w : maxCellSize.getLeft()) {
                totalWidth += w;
            }

            totalHeight = 0;
            for (int h : maxCellSize.getRight()) {
                totalHeight += h;
            }
        }

        if (elements > 0) {
            totalWidth += spacingX * (columns - 1);
        }
        if (elements > columns) {
            totalHeight += spacingY * (rows - 1);
        }
        return new Dimension(totalWidth, totalHeight);
    }

    private Pair<int[], int[]> calcNeededCellSize(GuiContainer<?> container) {
        int[] columnMaxWidth = new int[columns];
        int[] rowMaxHeight = new int[(container.getElements().size() - 1 + columns) / columns];

        int elements = 0;
        for (Map.Entry<GuiElement, LayoutData> entry : container.getElements().entrySet()) {
            int column = elements % columns;
            int row = elements / columns;

            GuiElement element = entry.getKey();
            ReadableDimension minSize = element.getMinSize();

            int width = minSize.getWidth();
            if (width > columnMaxWidth[column]) {
                columnMaxWidth[column] = width;
            }

            int height = minSize.getHeight();
            if (height > rowMaxHeight[row]) {
                rowMaxHeight[row] = height;
            }

            elements++;
        }

        return Pair.of(columnMaxWidth, rowMaxHeight);
    }

    @lombok.Data
    @AllArgsConstructor
    public static class Data implements LayoutData {
        private double alignmentX, alignmentY;

        public Data() {
            this(0, 0);
        }
    }
}