aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/pers/gwyog/gtneioreplugin/util/StringPaddingHack.java
blob: 20e524ec410b42d6a316d3a0ff86ab89970ada20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package pers.gwyog.gtneioreplugin.util;

import com.google.common.base.Strings;
import java.util.Arrays;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;

public class StringPaddingHack {
    private static final int SPACE_WIDTH = 4;
    private static final int BOLD_SPACE_WIDTH = 5;

    /**
     * Given a list of strings, arrange them into the requested number of columns with the specified spacing.
     * Up to 3 additional spaces might be added between columns because this function relies on quirky font behaviors.
     *
     * @param strings List of strings to wrap into columns
     * @param numColumns Number of columns, minimum of 1
     * @param minColumnSpacing Minimum amount of extra spaces between columns.
     * @return strings wrapped into columns
     */
    public static String[] stringsToSpacedColumns(String[] strings, int numColumns, int minColumnSpacing) {
        if (numColumns < 1) {
            throw new IllegalArgumentException(
                    String.format("Argument numColumns must be 1 or higher, got value %d", numColumns));
        }
        if (numColumns > 1) {
            int sliceSize = strings.length / numColumns;
            int remainder = strings.length % numColumns;
            String[][] columns = new String[numColumns][];
            int totalExtra = 0;

            // Arrange all strings into their proper columns so that the list of strings wraps through all columns
            for (int i = 0; i < numColumns; i++) {
                int extra = 0;
                if (remainder > 0) {
                    remainder--;
                    extra = 1;
                }
                columns[i] = Arrays.copyOfRange(
                        strings, (sliceSize * i) + totalExtra, (sliceSize * (i + 1) + totalExtra + extra));

                totalExtra += extra;
            }

            // Add extra padding to all but the last columns to align the text
            for (int i = 0; i < numColumns - 1; i++) {
                columns[i] = padStrings(columns[i], minColumnSpacing);
            }

            // Concatenate all columns into the final result
            strings = columns[0];
            for (int i = 0; i < sliceSize; i++) {
                for (int j = 1; j < numColumns; j++) {
                    strings[i] += columns[j][i];
                }
            }
        }

        return strings;
    }

    /**
     * Pads strings with spaces so that they are of equal length and adds to
     * that the number of spaces specified and up to 3 if minExtraSpaces is
     * below 3. Added spaces might be bold.
     *
     * Relies on the quirk of bold space characters being 1 pixel wider than
     * regular space characters in the default font renderer.
     *
     * @param strings List of strings
     * @param minExtraSpaces The minimum number of extra spaces to add
     * @return List of strings padded with spaces to an equal length
     */
    public static String[] padStrings(String[] strings, int minExtraSpaces) {
        int[] widths = getStringWidths(strings);
        int maxUnPaddedStrLength = 0;
        int numSpacesAddedToLongestString = 0;
        int maxPaddedStrLength = 0;

        // Making string width a multiple of 4 by adding bold spaces of width 5
        for (int i = 0; i < strings.length; i++) {
            int mod = widths[i] % SPACE_WIDTH;
            int numBoldSpacesToAdd = (SPACE_WIDTH - mod) % SPACE_WIDTH;

            // Keep track of the number of spaces added to the longest string
            if (widths[i] > maxUnPaddedStrLength) {
                numSpacesAddedToLongestString = numBoldSpacesToAdd;
                maxUnPaddedStrLength = widths[i];
            }

            strings[i] += "§l" + Strings.repeat(" ", numBoldSpacesToAdd) + "§r";
            widths[i] += numBoldSpacesToAdd * BOLD_SPACE_WIDTH;

            // Keep track of the current widest string we currently have
            if (widths[i] > maxPaddedStrLength) {
                maxPaddedStrLength = widths[i];
            }
        }

        // Make sure we pad at least up to the desired number of spaces from the longest string
        if (numSpacesAddedToLongestString < minExtraSpaces) {
            maxPaddedStrLength += (minExtraSpaces - numSpacesAddedToLongestString) * SPACE_WIDTH;
        }

        // Add required spaces to equalize length of all strings to at least the target width
        for (int i = 0; i < strings.length; i++) {
            int numSpacesToAdd = (maxPaddedStrLength - widths[i]) / SPACE_WIDTH;
            strings[i] += Strings.repeat(" ", numSpacesToAdd);
            widths[i] += numSpacesToAdd * SPACE_WIDTH;
        }

        return strings;
    }

    /**
     * Returns an array of font widths for the given array of strings
     *
     * @param strList Array of strings
     * @return Array of font widths
     */
    protected static int[] getStringWidths(String[] strList) {
        FontRenderer font = Minecraft.getMinecraft().fontRenderer;
        int[] widths = new int[strList.length];
        for (int i = 0; i < strList.length; ++i) {
            widths[i] = font.getStringWidth(strList[i]);
        }
        return widths;
    }
}