Improved GUIBuilder & ControlItems

This commit is contained in:
NichtStudioCode 2021-02-08 17:00:36 +01:00
parent b76be6ffd8
commit a973701bbc
24 changed files with 444 additions and 508 deletions

@ -0,0 +1,9 @@
package de.studiocode.invui.gui;
import de.studiocode.invui.item.impl.controlitem.ControlItem;
public interface Controllable {
void addControlItem(int index, ControlItem<?> controlItem);
}

@ -3,8 +3,6 @@ package de.studiocode.invui.gui;
import de.studiocode.invui.animation.Animation; import de.studiocode.invui.animation.Animation;
import de.studiocode.invui.gui.SlotElement.ItemStackHolder; import de.studiocode.invui.gui.SlotElement.ItemStackHolder;
import de.studiocode.invui.gui.builder.GUIBuilder; import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.gui.builder.PagedGUIBuilder;
import de.studiocode.invui.gui.builder.TabGUIBuilder;
import de.studiocode.invui.gui.impl.*; import de.studiocode.invui.gui.impl.*;
import de.studiocode.invui.item.Item; import de.studiocode.invui.item.Item;
import de.studiocode.invui.virtualinventory.VirtualInventory; import de.studiocode.invui.virtualinventory.VirtualInventory;
@ -38,8 +36,6 @@ import java.util.function.Predicate;
* @see SimplePagedGUIsGUI * @see SimplePagedGUIsGUI
* @see SimpleTabGUI * @see SimpleTabGUI
* @see GUIBuilder * @see GUIBuilder
* @see PagedGUIBuilder
* @see TabGUIBuilder
*/ */
public interface GUI extends GUIParent { public interface GUI extends GUIParent {

@ -2,15 +2,19 @@ package de.studiocode.invui.gui.builder;
import de.studiocode.invui.gui.GUI; import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement; import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.impl.SimpleGUI; import de.studiocode.invui.gui.SlotElement.ItemSlotElement;
import de.studiocode.invui.gui.impl.*;
import de.studiocode.invui.item.Item; 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.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import static de.studiocode.invui.gui.builder.GUIType.*;
/** /**
* A builder class to easily construct {@link GUI}s.<br> * A builder class to easily construct {@link GUI}s.<br>
@ -19,151 +23,138 @@ import java.util.Map;
*/ */
public class GUIBuilder { public class GUIBuilder {
protected final int width; private final GUIType guiType;
protected final int height; private final int width;
private final int size; private final int height;
private final HashMap<Character, Ingredient> ingredientMap = new HashMap<>();
private final Map<Character, Ingredient> ingredientMap = new HashMap<>();
private String structure; private String structure;
public GUIBuilder(int width, int height) { private List<Item> items = new ArrayList<>();
private List<GUI> guis = new ArrayList<>();
public GUIBuilder(@NotNull GUIType guiType, int width, int height) {
this.guiType = guiType;
this.width = width; this.width = width;
this.height = height; this.height = height;
this.size = width * height;
} }
/** public GUIBuilder setStructure(@NotNull String structure) {
* Builds the {@link GUI}. String trimmedStructure = structure
* .replace(" ", "")
* @return The built {@link GUI} .replace("\n", "");
*/
if (trimmedStructure.length() != width * height)
throw new IllegalArgumentException("Structure size does not match GUI size");
this.structure = trimmedStructure;
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));
return this;
}
public GUIBuilder setMarker(char key, @NotNull Marker marker) {
ingredientMap.put(key, new Ingredient(marker));
return this;
}
public GUIBuilder setItems(@NotNull List<Item> items) {
if (guiType != PAGED_ITEMS && guiType != SCROLL)
throw new UnsupportedOperationException("Items cannot be set in this gui type.");
this.items = items;
return this;
}
public GUIBuilder addItem(@NotNull Item item) {
if (guiType != PAGED_ITEMS && guiType != SCROLL)
throw new UnsupportedOperationException("Items cannot be set in this gui type.");
items.add(item);
return this;
}
public GUIBuilder setGUIs(@NotNull List<GUI> guis) {
if (guiType != PAGED_GUIs)
throw new UnsupportedOperationException("GUIs cannot be set in this gui type.");
this.guis = guis;
return this;
}
public GUIBuilder addGUI(@NotNull GUI gui) {
if (guiType != PAGED_GUIs)
throw new UnsupportedOperationException("GUIs cannot be set in this gui type.");
guis.add(gui);
return this;
}
public GUI build() { public GUI build() {
IngredientList ingredients = new IngredientList(structure, ingredientMap);
switch (guiType) {
case NORMAL:
return buildSimpleGUI(ingredients);
case PAGED_ITEMS:
return buildSimplePagedItemsGUI(ingredients);
case PAGED_GUIs:
return buildSimplePagedGUIsGUI(ingredients);
case TAB:
return buildSimpleTabGUI(ingredients);
case SCROLL:
return buildSimpleScrollGUI(ingredients);
default:
throw new UnsupportedOperationException("Unknown GUI type");
}
}
private SimpleGUI buildSimpleGUI(IngredientList ingredients) {
SimpleGUI gui = new SimpleGUI(width, height); SimpleGUI gui = new SimpleGUI(width, height);
setSlotElements(gui); ingredients.insertIntoGUI(gui);
return gui; return gui;
} }
/** private SimplePagedItemsGUI buildSimplePagedItemsGUI(IngredientList ingredients) {
* Sets the structure of the {@link GUI}. SimplePagedItemsGUI gui = new SimplePagedItemsGUI(width, height, items, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
* The structure is a {@link String} of characters, like used in {@link ShapedRecipe} to ingredients.insertIntoGUI(gui);
* define where which {@link Item} should be.
*
* @param structure The structure {@link String}
* @return The {@link GUIBuilder}
*/
public GUIBuilder setStructure(@NotNull String structure) {
String cleanedStructure = structure.replace(" ", "").replace("\n", "");
if (cleanedStructure.length() != size)
throw new IllegalArgumentException("Structure length does not match size");
this.structure = cleanedStructure;
return this; return gui;
} }
/** private SimplePagedGUIsGUI buildSimplePagedGUIsGUI(IngredientList ingredients) {
* Sets an ingredient for the structure String, which will later be SimplePagedGUIsGUI gui = new SimplePagedGUIsGUI(width, height, guis, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
* used to set up the inventory correctly. ingredients.insertIntoGUI(gui);
*
* @param key The ingredient key return gui;
* @param item The {@link Item}
* @return The {@link GUIBuilder}
*/
public GUIBuilder setIngredient(char key, @NotNull Item item) {
ingredientMap.put(key, new Ingredient(item));
return this;
} }
/** private SimpleTabGUI buildSimpleTabGUI(IngredientList ingredients) {
* Sets an ingredient for the structure String, which will later be SimpleTabGUI gui = new SimpleTabGUI(width, height, guis, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
* used to set up the inventory correctly. ingredients.insertIntoGUI(gui);
*
* @param key The ingredient key return gui;
* @param slotElement The {@link SlotElement}
* @return The {@link GUIBuilder}
*/
public GUIBuilder setIngredient(char key, @NotNull SlotElement slotElement) {
ingredientMap.put(key, new Ingredient(slotElement));
return this;
} }
protected void setIngredient(char key, int special) { private SimpleScrollGUI buildSimpleScrollGUI(IngredientList ingredients) {
ingredientMap.put(key, new Ingredient(special)); SimpleScrollGUI gui = new SimpleScrollGUI(width, height, items, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
} ingredients.insertIntoGUI(gui);
private Ingredient[] parseStructure() {
if (structure == null) throw new IllegalStateException("Structure has not been set yet.");
Ingredient[] ingredients = new Ingredient[size];
int i = 0;
for (char c : structure.toCharArray()) {
if (c != '.') ingredients[i] = this.ingredientMap.get(c);
i++;
}
return ingredients;
}
protected void setSlotElements(GUI gui) {
Ingredient[] ingredients = parseStructure();
for (int i = 0; i < gui.getSize(); i++) {
Ingredient ingredient = ingredients[i];
if (ingredient != null && ingredient.isSlotElement())
gui.setSlotElement(i, ingredient.getSlotElement());
}
}
protected int[] findIndicesOf(int special) {
List<Integer> indices = new ArrayList<>();
Ingredient[] ingredients = parseStructure();
for (int i = 0; i < size; i++) {
Ingredient ingredient = ingredients[i];
if (ingredient != null && ingredient.isSpecial() && ingredient.getSpecial() == special)
indices.add(i);
}
return indices.stream().mapToInt(Integer::intValue).toArray();
}
static class Ingredient {
private final SlotElement slotElement;
private final int special;
public Ingredient(Item item) {
this.slotElement = new SlotElement.ItemSlotElement(item);
this.special = -1;
}
public Ingredient(SlotElement slotElement) {
this.slotElement = slotElement;
this.special = -1;
}
public Ingredient(int special) {
this.special = special;
this.slotElement = null;
}
public SlotElement getSlotElement() {
if (isSpecial()) throw new IllegalStateException("Ingredient is special");
return slotElement;
}
public int getSpecial() {
if (isSlotElement()) throw new IllegalStateException("Ingredient is item");
return special;
}
public boolean isSlotElement() {
return slotElement != null;
}
public boolean isSpecial() {
return slotElement == null;
}
return gui;
} }
} }

@ -0,0 +1,11 @@
package de.studiocode.invui.gui.builder;
public enum GUIType {
NORMAL,
PAGED_ITEMS,
PAGED_GUIs,
TAB,
SCROLL
}

@ -0,0 +1,57 @@
package de.studiocode.invui.gui.builder;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import java.util.function.Function;
class Ingredient {
private final SlotElement slotElement;
private final Marker marker;
private final Function<GUI, ItemBuilder> builderFunction;
public Ingredient(SlotElement slotElement) {
this.slotElement = slotElement;
this.builderFunction = 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;
}
public SlotElement getSlotElement() {
return slotElement;
}
public Marker getMarker() {
return marker;
}
public Function<GUI, ItemBuilder> getBuilderFunction() {
return builderFunction;
}
public boolean isSlotElement() {
return slotElement != null;
}
public boolean isMarker() {
return marker != null;
}
public boolean isBuilderFunction() {
return builderFunction != null;
}
}

@ -0,0 +1,58 @@
package de.studiocode.invui.gui.builder;
import de.studiocode.invui.gui.Controllable;
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.controlitem.ControlItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
class IngredientList extends ArrayList<Ingredient> {
public IngredientList(String structure, HashMap<Character, Ingredient> ingredientMap) {
for (char c : structure.toCharArray()) {
Ingredient ingredient = null;
if (ingredientMap.containsKey(c)) ingredient = ingredientMap.get(c);
add(ingredient);
}
}
public void insertIntoGUI(GUI gui) {
for (int i = 0; i < size(); i++) {
Ingredient ingredient = get(i);
if (ingredient != null && ingredient.isSlotElement()) {
SlotElement slotElement = ingredient.getSlotElement();
if (gui instanceof Controllable && slotElement instanceof ItemSlotElement) {
Item item = ((ItemSlotElement) slotElement).getItem();
if (item instanceof ControlItem) {
((Controllable) gui).addControlItem(i, (ControlItem<?>) item);
continue;
}
}
gui.setSlotElement(i, ingredient.getSlotElement());
}
}
}
public List<Integer> findIndicesOfMarker(Marker marker) {
List<Integer> indices = new ArrayList<>();
for (int i = 0; i < size(); i++) {
Ingredient ingredient = get(i);
if (ingredient != null && ingredient.isMarker() && ingredient.getMarker() == marker)
indices.add(i);
}
return indices;
}
public int[] findIndicesOfMarkerAsArray(Marker marker) {
return findIndicesOfMarker(marker).stream().mapToInt(Integer::intValue).toArray();
}
}

@ -0,0 +1,7 @@
package de.studiocode.invui.gui.builder;
public enum Marker {
ITEM_LIST_SLOT
}

@ -1,119 +0,0 @@
package de.studiocode.invui.gui.builder;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.impl.PagedGUI;
import de.studiocode.invui.gui.impl.SimplePagedGUIsGUI;
import de.studiocode.invui.gui.impl.SimplePagedItemsGUI;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.function.Function;
public class PagedGUIBuilder extends GUIBuilder {
private final ContentType contentType;
private Function<PagedGUI, ItemBuilder> backFunction;
private Function<PagedGUI, ItemBuilder> forwardFunction;
private int[] listSlots;
private List<?> content;
public PagedGUIBuilder(ContentType contentType, int width, int height) {
super(width, height);
this.contentType = contentType;
}
@SuppressWarnings("unchecked")
@Override
public PagedGUI build() {
int[] listSlots = this.listSlots != null ? this.listSlots : findIndicesOf(2);
int[] backSlots = findIndicesOf(0);
int[] forwardSlots = findIndicesOf(1);
if (listSlots.length == 0) throw new IllegalStateException("No list slots have been set.");
if (backSlots.length == 0) throw new IllegalStateException("Not back slot has been set.");
if (forwardSlots.length == 0) throw new IllegalStateException("No forward slot has been set.");
if (content == null) throw new IllegalStateException("Content has not been set.");
if (forwardFunction == null) throw new IllegalStateException("Forward function has not been set.");
if (backFunction == null) throw new IllegalStateException("Back function has not been set");
int backSlot = backSlots[0];
int forwardSlot = forwardSlots[0];
PagedGUI gui;
if (contentType == ContentType.GUI) {
gui = new SimplePagedGUIsGUI(width, height, backSlot, backFunction,
forwardSlot, forwardFunction, (List<GUI>) content, listSlots);
} else {
gui = new SimplePagedItemsGUI(width, height, backSlot, backFunction,
forwardSlot, forwardFunction, (List<Item>) content, listSlots);
}
setSlotElements(gui);
return gui;
}
public PagedGUIBuilder setGUIs(List<GUI> guis) {
if (contentType != ContentType.GUI)
throw new IllegalStateException("Can't set guis if ContentType is not GUI");
content = guis;
return this;
}
public PagedGUIBuilder setItems(List<Item> items) {
if (contentType != ContentType.SINGLE_ITEMS)
throw new IllegalStateException("Can't set items if ContentType is not SINGLE_ITEMS");
content = items;
return this;
}
public PagedGUIBuilder setListSlots(int[] listSlots) {
this.listSlots = listSlots;
return this;
}
public PagedGUIBuilder setListSlotIngredient(char key) {
setIngredient(key, 2);
return this;
}
public PagedGUIBuilder setBackItem(char key, Function<PagedGUI, ItemBuilder> backFunction) {
setIngredient(key, 0);
this.backFunction = backFunction;
return this;
}
public PagedGUIBuilder setForwardItem(char key, Function<PagedGUI, ItemBuilder> forwardFunction) {
setIngredient(key, 1);
this.forwardFunction = forwardFunction;
return this;
}
@Override
public PagedGUIBuilder setStructure(@NotNull String structure) {
return (PagedGUIBuilder) super.setStructure(structure);
}
@Override
public PagedGUIBuilder setIngredient(char key, @NotNull Item item) {
return (PagedGUIBuilder) super.setIngredient(key, item);
}
@Override
public PagedGUIBuilder setIngredient(char key, @NotNull SlotElement slotElement) {
return (PagedGUIBuilder) super.setIngredient(key, slotElement);
}
public enum ContentType {
SINGLE_ITEMS,
GUI
}
}

@ -1,80 +0,0 @@
package de.studiocode.invui.gui.builder;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.impl.SimpleTabGUI;
import de.studiocode.invui.gui.impl.TabGUI;
import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.function.Function;
public class TabGUIBuilder extends GUIBuilder {
private final LinkedHashMap<GUI, Function<TabGUI, ItemBuilder>> tabs = new LinkedHashMap<>();
private int[] listSlots;
private int[] tabItemSlots;
public TabGUIBuilder(int width, int height) {
super(width, height);
}
@Override
public TabGUI build() {
int[] listSlots = this.listSlots != null ? this.listSlots : findIndicesOf(0);
int[] tabItemSlots = this.tabItemSlots != null ? this.tabItemSlots : findIndicesOf(1);
if (listSlots.length == 0) throw new IllegalStateException("No list slots have been set.");
if (tabItemSlots.length != tabs.size())
throw new IllegalStateException("TabItemSlots length has to be the same as tabs size");
SimpleTabGUI tabGUI = new SimpleTabGUI(width, height, tabs, listSlots, tabItemSlots);
setSlotElements(tabGUI);
return tabGUI;
}
public TabGUIBuilder addTab(GUI gui, Function<TabGUI, ItemBuilder> builderFunction) {
tabs.put(gui, builderFunction);
return this;
}
public TabGUIBuilder setListSlotIngredient(char key) {
setIngredient(key, 0);
return this;
}
public TabGUIBuilder setTabSlotIngredient(char key) {
setIngredient(key, 1);
return this;
}
public TabGUIBuilder setListSlots(int[] listSlots) {
this.listSlots = listSlots;
return this;
}
public TabGUIBuilder setTabItemSlots(int[] tabItemSlots) {
this.tabItemSlots = tabItemSlots;
return this;
}
@Override
public TabGUIBuilder setStructure(@NotNull String structure) {
return (TabGUIBuilder) super.setStructure(structure);
}
@Override
public TabGUIBuilder setIngredient(char key, @NotNull Item item) {
return (TabGUIBuilder) super.setIngredient(key, item);
}
@Override
public TabGUIBuilder setIngredient(char key, @NotNull SlotElement slotElement) {
return (TabGUIBuilder) super.setIngredient(key, slotElement);
}
}

@ -1,28 +1,29 @@
package de.studiocode.invui.gui.impl; package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.GUI; import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement; import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.builder.PagedGUIBuilder; import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.item.Item; import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.pagedgui.BackItem; import de.studiocode.invui.item.impl.controlitem.ControlItem;
import de.studiocode.invui.item.impl.pagedgui.ForwardItem; import de.studiocode.invui.item.impl.controlitem.PageItem;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* A {@link GUI} with pages. * A {@link GUI} with pages.
* *
* @see PagedGUIBuilder * @see GUIBuilder
* @see SimplePagedItemsGUI * @see SimplePagedItemsGUI
* @see SimplePagedGUIsGUI * @see SimplePagedGUIsGUI
*/ */
public abstract class PagedGUI extends BaseGUI { public abstract class PagedGUI extends BaseGUI implements Controllable {
private final List<Item> controlItems = new ArrayList<>();
private final boolean infinitePages; private final boolean infinitePages;
private final int[] itemListSlots; private final int[] itemListSlots;
protected int currentPage; protected int currentPage;
private Item forwardItem;
private Item backItem;
public PagedGUI(int width, int height, boolean infinitePages, int... itemListSlots) { public PagedGUI(int width, int height, boolean infinitePages, int... itemListSlots) {
super(width, height); super(width, height);
@ -30,9 +31,14 @@ public abstract class PagedGUI extends BaseGUI {
this.itemListSlots = itemListSlots; this.itemListSlots = itemListSlots;
} }
public void setControlItems(int backItemSlot, BackItem backItem, int forwardItemSlot, ForwardItem forwardItem) { @Override
setItem(backItemSlot, this.backItem = backItem); public void addControlItem(int index, ControlItem<?> controlItem) {
setItem(forwardItemSlot, this.forwardItem = forwardItem); if (!(controlItem instanceof PageItem))
throw new IllegalArgumentException("controlItem is not an instance of PageItem");
((PageItem) controlItem).setGui(this);
setItem(index, controlItem);
controlItems.add(controlItem);
} }
public void goForward() { public void goForward() {
@ -72,8 +78,7 @@ public abstract class PagedGUI extends BaseGUI {
} }
private void updateControlItems() { private void updateControlItems() {
backItem.notifyWindows(); controlItems.forEach(Item::notifyWindows);
forwardItem.notifyWindows();
} }
private void updatePageContent() { private void updatePageContent() {
@ -89,14 +94,6 @@ public abstract class PagedGUI extends BaseGUI {
return currentPage; return currentPage;
} }
public Item getForwardItem() {
return forwardItem;
}
public Item getBackItem() {
return backItem;
}
public boolean hasInfinitePages() { public boolean hasInfinitePages() {
return infinitePages; return infinitePages;
} }

@ -1,8 +1,12 @@
package de.studiocode.invui.gui.impl; package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.GUI; import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement; import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.item.Item; import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.controlitem.ControlItem;
import de.studiocode.invui.item.impl.controlitem.ScrollItem;
import de.studiocode.invui.util.SlotUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -12,7 +16,7 @@ import java.util.List;
* *
* @see SimpleScrollGUI * @see SimpleScrollGUI
*/ */
public abstract class ScrollGUI extends BaseGUI { public abstract class ScrollGUI extends BaseGUI implements Controllable {
private final List<Item> controlItems = new ArrayList<>(); private final List<Item> controlItems = new ArrayList<>();
private final boolean infiniteLines; private final boolean infiniteLines;
@ -21,12 +25,11 @@ public abstract class ScrollGUI extends BaseGUI {
protected int offset; protected int offset;
public ScrollGUI(int width, int height, boolean infiniteLines, int... itemListSlots) {
public ScrollGUI(int width, int height, boolean infiniteLines, int lineLength, int... itemListSlots) {
super(width, height); super(width, height);
this.infiniteLines = infiniteLines; this.infiniteLines = infiniteLines;
this.itemListSlots = itemListSlots; this.itemListSlots = itemListSlots;
this.lineLength = lineLength; this.lineLength = SlotUtils.getLongestLineLength(itemListSlots, width);
if (lineLength == 0) if (lineLength == 0)
throw new IllegalArgumentException("Line length can't be 0"); throw new IllegalArgumentException("Line length can't be 0");
@ -36,9 +39,14 @@ public abstract class ScrollGUI extends BaseGUI {
throw new IllegalArgumentException("itemListSlots has to be a multiple of lineLength"); throw new IllegalArgumentException("itemListSlots has to be a multiple of lineLength");
} }
public void addControlItem(int index, Item item) { @Override
controlItems.add(item); public void addControlItem(int index, ControlItem<?> controlItem) {
setItem(index, item); if (!(controlItem instanceof ScrollItem))
throw new IllegalArgumentException("controlItem is not an instance of ScrollItem");
((ScrollItem) controlItem).setGui(this);
setItem(index, controlItem);
controlItems.add(controlItem);
} }
public void setCurrentLine(int line) { public void setCurrentLine(int line) {

@ -2,36 +2,30 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.GUI; import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement; import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.builder.PagedGUIBuilder; import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.item.impl.pagedgui.BackItem;
import de.studiocode.invui.item.impl.pagedgui.ForwardItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.function.Function;
/** /**
* A {@link PagedGUI} where every page is it's own {@link GUI}. * A {@link PagedGUI} where every page is it's own {@link GUI}.
* *
* @see PagedGUIBuilder * @see GUIBuilder
* @see SimplePagedItemsGUI * @see SimplePagedItemsGUI
*/ */
public class SimplePagedGUIsGUI extends PagedGUI { public class SimplePagedGUIsGUI extends PagedGUI {
private List<GUI> guis; private List<GUI> guis;
public SimplePagedGUIsGUI(int width, int height, public SimplePagedGUIsGUI(int width, int height, int... itemListSlots) {
int backItemSlot, Function<PagedGUI, ItemBuilder> backFunction, this(width, height, new ArrayList<>(), itemListSlots);
int forwardItemSlot, Function<PagedGUI, ItemBuilder> forwardFunction, }
List<GUI> guis, int... itemListSlots) {
public SimplePagedGUIsGUI(int width, int height, List<GUI> guis, int... itemListSlots) {
super(width, height, false, itemListSlots); super(width, height, false, itemListSlots);
this.guis = guis; this.guis = guis;
setControlItems(backItemSlot, new BackItem(this, backFunction),
forwardItemSlot, new ForwardItem(this, forwardFunction));
update(); update();
} }

@ -2,36 +2,31 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.SlotElement; import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.SlotElement.ItemSlotElement; import de.studiocode.invui.gui.SlotElement.ItemSlotElement;
import de.studiocode.invui.gui.builder.PagedGUIBuilder; import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.item.Item; import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.pagedgui.BackItem;
import de.studiocode.invui.item.impl.pagedgui.ForwardItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* A {@link PagedGUI} that is filled with {@link Item}s. * A {@link PagedGUI} that is filled with {@link Item}s.
* *
* @see PagedGUIBuilder * @see GUIBuilder
* @see SimplePagedGUIsGUI * @see SimplePagedGUIsGUI
*/ */
public class SimplePagedItemsGUI extends PagedGUI { public class SimplePagedItemsGUI extends PagedGUI {
private List<Item> items; private List<Item> items;
public SimplePagedItemsGUI(int width, int height, public SimplePagedItemsGUI(int width, int height, int... itemListSlots) {
int backItemSlot, Function<PagedGUI, ItemBuilder> backFunction, this(width, height, new ArrayList<>(), itemListSlots);
int forwardItemSlot, Function<PagedGUI, ItemBuilder> forwardFunction, }
List<Item> items, int... itemListSlots) {
public SimplePagedItemsGUI(int width, int height, List<Item> items, int... itemListSlots) {
super(width, height, false, itemListSlots); super(width, height, false, itemListSlots);
this.items = items; this.items = items;
setControlItems(backItemSlot, new BackItem(this, backFunction),
forwardItemSlot, new ForwardItem(this, forwardFunction));
update(); update();
} }
@ -53,4 +48,5 @@ public class SimplePagedItemsGUI extends PagedGUI {
this.items = items; this.items = items;
update(); update();
} }
} }

@ -10,8 +10,8 @@ public class SimpleScrollGUI extends ScrollGUI {
private List<Item> items; private List<Item> items;
public SimpleScrollGUI(int width, int height, List<Item> items, int lineLength, int... itemListSlots) { public SimpleScrollGUI(int width, int height, List<Item> items, int... itemListSlots) {
super(width, height, false, lineLength, itemListSlots); super(width, height, false, itemListSlots);
this.items = items; this.items = items;
update(); update();

@ -2,36 +2,23 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.GUI; import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement; import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.builder.TabGUIBuilder; import de.studiocode.invui.gui.builder.GUIBuilder;
import de.studiocode.invui.item.impl.tabgui.TabItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.function.Function;
/** /**
* A {@link GUI} that has multiple tabs with which users can switch between {@link GUI}s. * A {@link GUI} that has multiple tabs with which users can switch between {@link GUI}s.
* *
* @see TabGUIBuilder * @see GUIBuilder
*/ */
public class SimpleTabGUI extends TabGUI { public class SimpleTabGUI extends TabGUI {
private final List<GUI> tabs; private final List<GUI> tabs;
public SimpleTabGUI(int width, int height, LinkedHashMap<GUI, Function<TabGUI, ItemBuilder>> tabs, public SimpleTabGUI(int width, int height, List<GUI> tabs, int[] listSlots) {
int[] listSlots, int[] tabItemSlots) {
super(width, height, tabs.size(), listSlots); super(width, height, tabs.size(), listSlots);
this.tabs = new ArrayList<>(tabs.keySet()); this.tabs = tabs;
List<Function<TabGUI, ItemBuilder>> builderFunctions = new ArrayList<>(tabs.values());
for (int i = 0; i < tabs.size(); i++) {
TabItem tabItem = new TabItem(this, i, builderFunctions.get(i));
setTabItem(i, tabItemSlots[i], tabItem);
}
update(); update();
} }

@ -1,17 +1,19 @@
package de.studiocode.invui.gui.impl; package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.SlotElement; import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.item.Item; import de.studiocode.invui.item.Item;
import de.studiocode.invui.item.impl.tabgui.TabItem; import de.studiocode.invui.item.impl.controlitem.ControlItem;
import de.studiocode.invui.item.impl.controlitem.TabItem;
import java.util.Arrays; import java.util.ArrayList;
import java.util.List; import java.util.List;
public abstract class TabGUI extends BaseGUI { public abstract class TabGUI extends BaseGUI implements Controllable {
private final List<Item> controlItems = new ArrayList<>();
private final int tabAmount; private final int tabAmount;
private final int[] listSlots; private final int[] listSlots;
private final Item[] tabItems;
private int currentTab; private int currentTab;
@ -19,7 +21,6 @@ public abstract class TabGUI extends BaseGUI {
super(width, height); super(width, height);
this.tabAmount = tabAmount; this.tabAmount = tabAmount;
this.listSlots = listSlots; this.listSlots = listSlots;
this.tabItems = new Item[tabAmount];
} }
public void showTab(int tab) { public void showTab(int tab) {
@ -30,14 +31,26 @@ public abstract class TabGUI extends BaseGUI {
update(); update();
} }
public void setTabItem(int tab, int index, TabItem tabItem) { @Override
tabItems[tab] = tabItem; public void addControlItem(int index, ControlItem<?> controlItem) {
setItem(index, tabItem); if (!(controlItem instanceof TabItem))
throw new IllegalArgumentException("controlItem is not an instance of TabItem");
((TabItem) controlItem).setGui(this);
setItem(index, controlItem);
controlItems.add(controlItem);
} }
protected void update() { protected void update() {
Arrays.stream(tabItems).forEach(Item::notifyWindows); updateControlItems();
updateContent();
}
private void updateControlItems() {
controlItems.forEach(Item::notifyWindows);
}
private void updateContent() {
List<SlotElement> slotElements = getSlotElements(currentTab); List<SlotElement> slotElements = getSlotElements(currentTab);
for (int i = 0; i < listSlots.length; i++) { for (int i = 0; i < listSlots.length; i++) {
int slot = listSlots[i]; int slot = listSlots[i];

@ -1,34 +0,0 @@
package de.studiocode.invui.item.impl;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function;
public class FunctionItem<T> extends BaseItem {
private final T t;
private final Function<T, ItemBuilder> builderFunction;
public FunctionItem(T t, Function<T, ItemBuilder> builderFunction) {
this.t = t;
this.builderFunction = builderFunction;
}
@Override
public ItemBuilder getItemBuilder() {
return builderFunction.apply(t);
}
public T getT() {
return t;
}
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
// empty
}
}

@ -0,0 +1,31 @@
package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.item.impl.BaseItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import java.util.function.Function;
public abstract class ControlItem<G extends GUI> extends BaseItem {
private G gui;
private final Function<G, ItemBuilder> builderFunction;
public ControlItem(Function<G, ItemBuilder> builderFunction) {
this.builderFunction = builderFunction;
}
@Override
public ItemBuilder getItemBuilder() {
return builderFunction.apply(gui);
}
public G getGui() {
return gui;
}
public void setGui(G gui) {
this.gui = gui;
}
}

@ -0,0 +1,31 @@
package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.impl.PagedGUI;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function;
/**
* Switches between pages in a {@link PagedGUI}
*/
public class PageItem extends ControlItem<PagedGUI> {
private final boolean forward;
public PageItem(boolean forward, Function<PagedGUI, ItemBuilder> builderFunction) {
super(builderFunction);
this.forward = forward;
}
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
if (clickType == ClickType.LEFT) {
if (forward) getGui().goForward();
else getGui().goBack();
}
}
}

@ -1,7 +1,6 @@
package de.studiocode.invui.item.impl.scrollgui; package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.impl.ScrollGUI; import de.studiocode.invui.gui.impl.ScrollGUI;
import de.studiocode.invui.item.impl.FunctionItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder; import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
@ -10,25 +9,27 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.Function; import java.util.function.Function;
public class ScrollItem extends FunctionItem<ScrollGUI> { /**
* Scrolls in a {@link ScrollGUI}
*/
public class ScrollItem extends ControlItem<ScrollGUI> {
private final HashMap<ClickType, Integer> scroll; private final HashMap<ClickType, Integer> scroll;
public ScrollItem(ScrollGUI scrollGUI, int scrollLeftClick, Function<ScrollGUI, ItemBuilder> builderFunction) { public ScrollItem(int scrollLeftClick, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(scrollGUI, builderFunction); super(builderFunction);
scroll = new HashMap<>(); scroll = new HashMap<>();
scroll.put(ClickType.LEFT, scrollLeftClick); scroll.put(ClickType.LEFT, scrollLeftClick);
} }
public ScrollItem(ScrollGUI scrollGUI, HashMap<ClickType, Integer> scroll, Function<ScrollGUI, ItemBuilder> builderFunction) { public ScrollItem(HashMap<ClickType, Integer> scroll, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(scrollGUI, builderFunction); super(builderFunction);
this.scroll = scroll; this.scroll = scroll;
} }
@Override @Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) { public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
if (scroll.containsKey(clickType)) getT().scroll(scroll.get(clickType)); if (scroll.containsKey(clickType)) getGui().scroll(scroll.get(clickType));
} }
} }

@ -1,7 +1,6 @@
package de.studiocode.invui.item.impl.tabgui; package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.impl.TabGUI; import de.studiocode.invui.gui.impl.TabGUI;
import de.studiocode.invui.item.impl.FunctionItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder; import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
@ -9,18 +8,21 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function; import java.util.function.Function;
public class TabItem extends FunctionItem<TabGUI> { /**
* Switches between tabs in a {@link TabGUI}
*/
public class TabItem extends ControlItem<TabGUI> {
private final int tab; private final int tab;
public TabItem(TabGUI tabGUI, int tab, Function<TabGUI, ItemBuilder> builderFunction) { public TabItem(int tab, Function<TabGUI, ItemBuilder> builderFunction) {
super(tabGUI, builderFunction); super(builderFunction);
this.tab = tab; this.tab = tab;
} }
@Override @Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) { public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
if (clickType == ClickType.LEFT) getT().showTab(tab); if (clickType == ClickType.LEFT) getGui().showTab(tab);
} }
} }

@ -1,23 +0,0 @@
package de.studiocode.invui.item.impl.pagedgui;
import de.studiocode.invui.gui.impl.PagedGUI;
import de.studiocode.invui.item.impl.FunctionItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function;
public class BackItem extends FunctionItem<PagedGUI> {
public BackItem(PagedGUI pagedGUI, Function<PagedGUI, ItemBuilder> builderFunction) {
super(pagedGUI, builderFunction);
}
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
if (clickType == ClickType.LEFT) getT().goBack();
}
}

@ -1,23 +0,0 @@
package de.studiocode.invui.item.impl.pagedgui;
import de.studiocode.invui.gui.impl.PagedGUI;
import de.studiocode.invui.item.impl.FunctionItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function;
public class ForwardItem extends FunctionItem<PagedGUI> {
public ForwardItem(PagedGUI pagedGUI, Function<PagedGUI, ItemBuilder> builderFunction) {
super(pagedGUI, builderFunction);
}
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
if (clickType == ClickType.LEFT) getT().goForward();
}
}

@ -1,7 +1,9 @@
package de.studiocode.invui.util; package de.studiocode.invui.util;
import java.util.Arrays;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
public class SlotUtils { public class SlotUtils {
@ -75,6 +77,30 @@ public class SlotUtils {
else return slot + 9; else return slot + 9;
} }
public static int getLongestLineLength(int[] slots, int frameWidth) {
int longestLength = 0;
int currentLength = 1;
Point2D previous = null;
for (Point2D point : Arrays.stream(slots)
.mapToObj(index -> convertFromIndex(index, frameWidth))
.collect(Collectors.toList())) {
if (previous != null) {
if (isNeighbor(previous, point)) currentLength++;
else currentLength = 1;
}
previous = point;
longestLength = Math.max(longestLength, currentLength);
}
return longestLength;
}
public static boolean isNeighbor(Point2D point1, Point2D point2) {
return Math.abs(point1.getX() - point2.getX()) + Math.abs(point1.getY() - point2.getY()) == 1;
}
public enum Order { public enum Order {
HORIZONTAL, HORIZONTAL,