Made Structure independent from GUIBuilder

This commit is contained in:
NichtStudioCode 2021-02-11 21:48:45 +01:00
parent bd625c3adb
commit 459f19d7b3
16 changed files with 240 additions and 103 deletions

@ -4,6 +4,7 @@ import de.studiocode.invui.animation.Animation;
import de.studiocode.invui.gui.SlotElement.ItemStackHolder;
import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.gui.impl.*;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.virtualinventory.VirtualInventory;
import de.studiocode.invui.window.Window;
@ -195,6 +196,13 @@ public interface GUI extends GUIParent {
*/
void remove(int index);
/**
* Applies the given {@link Structure} to the {@link GUI}.
*
* @param structure The structure
*/
void applyStructure(Structure structure);
/**
* A method called if a slot in the {@link Inventory} has been clicked.
*

@ -2,17 +2,17 @@ package de.studiocode.invui.gui.builder;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.SlotElement.ItemSlotElement;
import de.studiocode.invui.gui.impl.*;
import de.studiocode.invui.gui.structure.Marker;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.SimpleItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Supplier;
import static de.studiocode.invui.gui.builder.GUIType.*;
@ -26,9 +26,8 @@ public class GUIBuilder {
private final GUIType guiType;
private final int width;
private final int height;
private final HashMap<Character, Ingredient> ingredientMap = new HashMap<>();
private String structure;
private Structure structure;
private List<Item> items = new ArrayList<>();
private List<GUI> guis = new ArrayList<>();
@ -39,33 +38,38 @@ public class GUIBuilder {
this.height = height;
}
public GUIBuilder setStructure(@NotNull String structure) {
String trimmedStructure = structure
.replace(" ", "")
.replace("\n", "");
if (trimmedStructure.length() != width * height)
throw new IllegalArgumentException("Structure size does not match GUI size");
this.structure = trimmedStructure;
public GUIBuilder setStructure(@NotNull String structureData) {
this.structure = new Structure(structureData);
return this;
}
public GUIBuilder setIngredient(char key, @NotNull ItemBuilder itemBuilder) {
return setIngredient(key, new SimpleItem(itemBuilder));
}
public GUIBuilder setIngredient(char key, @NotNull Item item) {
return setIngredient(key, new ItemSlotElement(item));
}
public GUIBuilder setIngredient(char key, @NotNull SlotElement element) {
ingredientMap.put(key, new Ingredient(element));
public GUIBuilder setStructure(@NotNull Structure structure) {
this.structure = structure;
return this;
}
public GUIBuilder setMarker(char key, @NotNull Marker marker) {
ingredientMap.put(key, new Ingredient(marker));
public GUIBuilder addIngredient(char key, @NotNull ItemBuilder itemBuilder) {
structure.addIngredient(key, itemBuilder);
return this;
}
public GUIBuilder addIngredient(char key, @NotNull Item item) {
structure.addIngredient(key, item);
return this;
}
public GUIBuilder addIngredient(char key, @NotNull SlotElement element) {
structure.addIngredient(key, element);
return this;
}
public GUIBuilder addIngredient(char key, @NotNull Marker marker) {
structure.addIngredient(key, marker);
return this;
}
public GUIBuilder addIngredient(char key, @NotNull Supplier<Item> itemSupplier) {
structure.addIngredient(key, itemSupplier);
return this;
}
@ -98,63 +102,46 @@ public class GUIBuilder {
}
public GUI build() {
IngredientList ingredients = new IngredientList(structure, ingredientMap);
switch (guiType) {
case NORMAL:
return buildSimpleGUI(ingredients);
return buildSimpleGUI();
case PAGED_ITEMS:
return buildSimplePagedItemsGUI(ingredients);
return buildSimplePagedItemsGUI();
case PAGED_GUIs:
return buildSimplePagedGUIsGUI(ingredients);
return buildSimplePagedGUIsGUI();
case TAB:
return buildSimpleTabGUI(ingredients);
return buildSimpleTabGUI();
case SCROLL:
return buildSimpleScrollGUI(ingredients);
return buildSimpleScrollGUI();
default:
throw new UnsupportedOperationException("Unknown GUI type");
}
}
private SimpleGUI buildSimpleGUI(IngredientList ingredients) {
SimpleGUI gui = new SimpleGUI(width, height);
ingredients.insertIntoGUI(gui);
return gui;
private SimpleGUI buildSimpleGUI() {
return new SimpleGUI(width, height, structure);
}
private SimplePagedItemsGUI buildSimplePagedItemsGUI(IngredientList ingredients) {
SimplePagedItemsGUI gui = new SimplePagedItemsGUI(width, height, items, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
return gui;
private SimplePagedItemsGUI buildSimplePagedItemsGUI() {
return new SimplePagedItemsGUI(width, height, items, structure);
}
private SimplePagedGUIsGUI buildSimplePagedGUIsGUI(IngredientList ingredients) {
SimplePagedGUIsGUI gui = new SimplePagedGUIsGUI(width, height, guis, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
return gui;
private SimplePagedGUIsGUI buildSimplePagedGUIsGUI() {
return new SimplePagedGUIsGUI(width, height, guis, structure);
}
private SimpleTabGUI buildSimpleTabGUI(IngredientList ingredients) {
SimpleTabGUI gui = new SimpleTabGUI(width, height, guis, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
return gui;
private SimpleTabGUI buildSimpleTabGUI() {
return new SimpleTabGUI(width, height, guis, structure);
}
private SimpleScrollGUI buildSimpleScrollGUI(IngredientList ingredients) {
SimpleScrollGUI gui = new SimpleScrollGUI(width, height, items, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
return gui;
private SimpleScrollGUI buildSimpleScrollGUI() {
return new SimpleScrollGUI(width, height, items, structure);
}
}

@ -8,6 +8,7 @@ import de.studiocode.invui.gui.SlotElement.ItemSlotElement;
import de.studiocode.invui.gui.SlotElement.ItemStackHolder;
import de.studiocode.invui.gui.SlotElement.LinkedSlotElement;
import de.studiocode.invui.gui.SlotElement.VISlotElement;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.util.ArrayUtils;
import de.studiocode.invui.virtualinventory.VirtualInventory;
@ -375,6 +376,11 @@ abstract class IndexedGUI implements GUI {
setSlotElement(index, null);
}
@Override
public void applyStructure(Structure structure) {
structure.createIngredientList().insertIntoGUI(this);
}
@Override
public int getSize() {
return size;

@ -4,6 +4,8 @@ import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.gui.structure.Marker;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.controlitem.ControlItem;
import de.studiocode.invui.item.impl.controlitem.PageItem;
@ -31,6 +33,11 @@ public abstract class PagedGUI extends BaseGUI implements Controllable {
this.itemListSlots = itemListSlots;
}
public PagedGUI(int width, int height, boolean infinitePages, Structure structure) {
this(width, height, infinitePages, structure.createIngredientList().findIndicesOfMarker(Marker.ITEM_LIST_SLOT));
applyStructure(structure);
}
@Override
public void addControlItem(int index, ControlItem<?> controlItem) {
if (!(controlItem instanceof PageItem))

@ -3,6 +3,8 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.structure.Marker;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.controlitem.ControlItem;
import de.studiocode.invui.item.impl.controlitem.ScrollItem;
@ -39,6 +41,11 @@ public abstract class ScrollGUI extends BaseGUI implements Controllable {
throw new IllegalArgumentException("itemListSlots has to be a multiple of lineLength");
}
public ScrollGUI(int width, int height, boolean infiniteLines, Structure structure) {
this(width, height, infiniteLines, structure.createIngredientList().findIndicesOfMarker(Marker.ITEM_LIST_SLOT));
applyStructure(structure);
}
@Override
public void addControlItem(int index, ControlItem<?> controlItem) {
if (!(controlItem instanceof ScrollItem))

@ -1,6 +1,8 @@
package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.structure.Structure;
import org.jetbrains.annotations.NotNull;
/**
* A normal {@link GUI} without any special features.
@ -11,4 +13,9 @@ public class SimpleGUI extends BaseGUI {
super(width, height);
}
public SimpleGUI(int width, int height, @NotNull Structure structure) {
super(width, height);
applyStructure(structure);
}
}

@ -3,6 +3,9 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.gui.structure.Structure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
@ -18,13 +21,16 @@ public class SimplePagedGUIsGUI extends PagedGUI {
private List<GUI> guis;
public SimplePagedGUIsGUI(int width, int height, int... itemListSlots) {
this(width, height, new ArrayList<>(), itemListSlots);
public SimplePagedGUIsGUI(int width, int height, @Nullable List<GUI> guis, int... itemListSlots) {
super(width, height, false, itemListSlots);
this.guis = guis == null ? new ArrayList<>() : guis;
update();
}
public SimplePagedGUIsGUI(int width, int height, List<GUI> guis, int... itemListSlots) {
super(width, height, false, itemListSlots);
this.guis = guis;
public SimplePagedGUIsGUI(int width, int height, @Nullable List<GUI> guis, @NotNull Structure structure) {
super(width, height, false, structure);
this.guis = guis == null ? new ArrayList<>() : guis;
update();
}

@ -3,7 +3,10 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.SlotElement.ItemSlotElement;
import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@ -19,13 +22,16 @@ public class SimplePagedItemsGUI extends PagedGUI {
private List<Item> items;
public SimplePagedItemsGUI(int width, int height, int... itemListSlots) {
this(width, height, new ArrayList<>(), itemListSlots);
public SimplePagedItemsGUI(int width, int height, @Nullable List<Item> items, int... itemListSlots) {
super(width, height, false, itemListSlots);
this.items = items == null ? new ArrayList<>() : items;
update();
}
public SimplePagedItemsGUI(int width, int height, List<Item> items, int... itemListSlots) {
super(width, height, false, itemListSlots);
this.items = items;
public SimplePagedItemsGUI(int width, int height, @Nullable List<Item> items, @NotNull Structure structure) {
super(width, height, false, structure);
this.items = items == null ? new ArrayList<>() : items;
update();
}

@ -1,8 +1,12 @@
package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -10,9 +14,16 @@ public class SimpleScrollGUI extends ScrollGUI {
private List<Item> items;
public SimpleScrollGUI(int width, int height, List<Item> items, int... itemListSlots) {
public SimpleScrollGUI(int width, int height, @Nullable List<Item> items, int... itemListSlots) {
super(width, height, false, itemListSlots);
this.items = items;
this.items = items == null ? new ArrayList<>() : items;
update();
}
public SimpleScrollGUI(int width, int height, @Nullable List<Item> items, @NotNull Structure structure) {
super(width, height, false, structure);
this.items = items == null ? new ArrayList<>() : items;
update();
}

@ -3,6 +3,8 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.gui.structure.Structure;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.List;
@ -16,13 +18,20 @@ public class SimpleTabGUI extends TabGUI {
private final List<GUI> tabs;
public SimpleTabGUI(int width, int height, List<GUI> tabs, int[] listSlots) {
public SimpleTabGUI(int width, int height, @NotNull List<GUI> tabs, int[] listSlots) {
super(width, height, tabs.size(), listSlots);
this.tabs = tabs;
update();
}
public SimpleTabGUI(int width, int height, @NotNull List<GUI> tabs, @NotNull Structure structure) {
super(width, height, tabs.size(), structure);
this.tabs = tabs;
update();
}
@Override
public List<SlotElement> getSlotElements(int tab) {
return Arrays.asList(tabs.get(tab).getSlotElements());

@ -2,6 +2,8 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.structure.Marker;
import de.studiocode.invui.gui.structure.Structure;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.controlitem.ControlItem;
import de.studiocode.invui.item.impl.controlitem.TabItem;
@ -23,6 +25,11 @@ public abstract class TabGUI extends BaseGUI implements Controllable {
this.listSlots = listSlots;
}
public TabGUI(int width, int height, int tabAmount, Structure structure) {
this(width, height, tabAmount, structure.createIngredientList().findIndicesOfMarker(Marker.ITEM_LIST_SLOT));
applyStructure(structure);
}
public void showTab(int tab) {
if (tab < 0 || tab >= tabAmount)
throw new IllegalArgumentException("Tab out of bounds");

@ -1,57 +1,49 @@
package de.studiocode.invui.gui.builder;
package de.studiocode.invui.gui.structure;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import de.studiocode.invui.gui.SlotElement.ItemSlotElement;
import de.studiocode.invui.item.Item;
import java.util.function.Function;
import java.util.function.Supplier;
class Ingredient {
private final SlotElement slotElement;
private final Marker marker;
private final Function<GUI, ItemBuilder> builderFunction;
private final Supplier<Item> itemSupplier;
public Ingredient(SlotElement slotElement) {
this.slotElement = slotElement;
this.builderFunction = null;
this.itemSupplier = null;
this.marker = null;
}
public Ingredient(Supplier<Item> itemSupplier) {
this.itemSupplier = itemSupplier;
this.slotElement = null;
this.marker = null;
}
public Ingredient(Marker marker) {
this.marker = marker;
this.slotElement = null;
this.builderFunction = null;
}
public Ingredient(Function<GUI, ItemBuilder> builderFunction) {
this.builderFunction = builderFunction;
this.slotElement = null;
this.marker = null;
this.itemSupplier = null;
}
public SlotElement getSlotElement() {
return slotElement;
return slotElement == null ? new ItemSlotElement(itemSupplier.get()) : slotElement;
}
public Marker getMarker() {
return marker;
}
public Function<GUI, ItemBuilder> getBuilderFunction() {
return builderFunction;
}
public boolean isSlotElement() {
return slotElement != null;
return slotElement != null || itemSupplier != null;
}
public boolean isMarker() {
return marker != null;
}
public boolean isBuilderFunction() {
return builderFunction != null;
}
}

@ -1,4 +1,4 @@
package de.studiocode.invui.gui.builder;
package de.studiocode.invui.gui.structure;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.GUI;
@ -11,7 +11,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
class IngredientList extends ArrayList<Ingredient> {
public class IngredientList extends ArrayList<Ingredient> {
public IngredientList(String structure, HashMap<Character, Ingredient> ingredientMap) {
for (char c : structure.toCharArray()) {
@ -22,6 +22,9 @@ class IngredientList extends ArrayList<Ingredient> {
}
public void insertIntoGUI(GUI gui) {
if (size() != gui.getSize())
throw new IllegalArgumentException("Structure size does not match GUI size");
for (int i = 0; i < size(); i++) {
Ingredient ingredient = get(i);
if (ingredient != null && ingredient.isSlotElement()) {
@ -40,7 +43,7 @@ class IngredientList extends ArrayList<Ingredient> {
}
}
public List<Integer> findIndicesOfMarker(Marker marker) {
public int[] findIndicesOfMarker(Marker marker) {
List<Integer> indices = new ArrayList<>();
for (int i = 0; i < size(); i++) {
Ingredient ingredient = get(i);
@ -48,11 +51,7 @@ class IngredientList extends ArrayList<Ingredient> {
indices.add(i);
}
return indices;
}
public int[] findIndicesOfMarkerAsArray(Marker marker) {
return findIndicesOfMarker(marker).stream().mapToInt(Integer::intValue).toArray();
return indices.stream().mapToInt(Integer::intValue).toArray();
}
}

@ -1,4 +1,4 @@
package de.studiocode.invui.gui.builder;
package de.studiocode.invui.gui.structure;
public enum Marker {

@ -0,0 +1,82 @@
package de.studiocode.invui.gui.structure;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.SlotElement.ItemSlotElement;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.SimpleItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.function.Supplier;
/**
* Provides an easy way to design {@link GUI}s.
* Inspired by Bukkit's {@link ShapedRecipe}, this class will let you
* design a {@link GUI} in a similar way.
*/
public class Structure {
private static final HashMap<Character, Ingredient> globalIngredientMap = new HashMap<>();
private final HashMap<Character, Ingredient> ingredientMap = new HashMap<>();
private final String structureData;
public Structure(String structureData) {
this.structureData = structureData
.replace(" ", "")
.replace("\n", "");
}
public static void addGlobalIngredient(char key, @NotNull ItemBuilder itemBuilder) {
addGlobalIngredient(key, new SimpleItem(itemBuilder));
}
public static void addGlobalIngredient(char key, @NotNull Item item) {
addGlobalIngredient(key, new ItemSlotElement(item));
}
public static void addGlobalIngredient(char key, @NotNull SlotElement element) {
globalIngredientMap.put(key, new Ingredient(element));
}
public static void addGlobalIngredient(char key, @NotNull Marker marker) {
globalIngredientMap.put(key, new Ingredient(marker));
}
public static void addGlobalIngredient(char key, @NotNull Supplier<Item> itemSupplier) {
globalIngredientMap.put(key, new Ingredient(itemSupplier));
}
public Structure addIngredient(char key, @NotNull ItemBuilder itemBuilder) {
return addIngredient(key, new SimpleItem(itemBuilder));
}
public Structure addIngredient(char key, @NotNull Item item) {
return addIngredient(key, new ItemSlotElement(item));
}
public Structure addIngredient(char key, @NotNull SlotElement element) {
ingredientMap.put(key, new Ingredient(element));
return this;
}
public Structure addIngredient(char key, @NotNull Marker marker) {
ingredientMap.put(key, new Ingredient(marker));
return this;
}
public Structure addIngredient(char key, @NotNull Supplier<Item> itemSupplier) {
ingredientMap.put(key, new Ingredient(itemSupplier));
return this;
}
public IngredientList createIngredientList() {
HashMap<Character, Ingredient> ingredients = new HashMap<>(globalIngredientMap);
this.ingredientMap.forEach(ingredients::put);
return new IngredientList(structureData, ingredients);
}
}

@ -25,6 +25,9 @@ public abstract class ControlItem<G extends GUI> extends BaseItem {
}
public void setGui(G gui) {
if (this.gui != null)
throw new IllegalStateException("The GUI is already set. (One ControlItem can't control multiple GUIs)");
this.gui = gui;
}