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.gui.SlotElement.ItemStackHolder;
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.item.Item;
import de.studiocode.invui.virtualinventory.VirtualInventory;
@ -38,8 +36,6 @@ import java.util.function.Predicate;
* @see SimplePagedGUIsGUI
* @see SimpleTabGUI
* @see GUIBuilder
* @see PagedGUIBuilder
* @see TabGUIBuilder
*/
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.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.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.Map;
import static de.studiocode.invui.gui.builder.GUIType.*;
/**
* A builder class to easily construct {@link GUI}s.<br>
@ -19,151 +23,138 @@ import java.util.Map;
*/
public class GUIBuilder {
protected final int width;
protected final int height;
private final int size;
private final Map<Character, Ingredient> ingredientMap = new HashMap<>();
private final GUIType guiType;
private final int width;
private final int height;
private final HashMap<Character, Ingredient> ingredientMap = new HashMap<>();
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.height = height;
this.size = width * height;
}
/**
* Builds the {@link GUI}.
*
* @return The built {@link GUI}
*/
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;
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() {
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);
setSlotElements(gui);
ingredients.insertIntoGUI(gui);
return gui;
}
/**
* Sets the structure of the {@link GUI}.
* The structure is a {@link String} of characters, like used in {@link ShapedRecipe} to
* 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;
private SimplePagedItemsGUI buildSimplePagedItemsGUI(IngredientList ingredients) {
SimplePagedItemsGUI gui = new SimplePagedItemsGUI(width, height, items, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
return this;
return gui;
}
/**
* Sets an ingredient for the structure String, which will later be
* used to set up the inventory correctly.
*
* @param key The ingredient key
* @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 SimplePagedGUIsGUI buildSimplePagedGUIsGUI(IngredientList ingredients) {
SimplePagedGUIsGUI gui = new SimplePagedGUIsGUI(width, height, guis, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
return gui;
}
/**
* Sets an ingredient for the structure String, which will later be
* used to set up the inventory correctly.
*
* @param key The ingredient key
* @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;
private SimpleTabGUI buildSimpleTabGUI(IngredientList ingredients) {
SimpleTabGUI gui = new SimpleTabGUI(width, height, guis, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
return gui;
}
protected void setIngredient(char key, int special) {
ingredientMap.put(key, new Ingredient(special));
}
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;
}
private SimpleScrollGUI buildSimpleScrollGUI(IngredientList ingredients) {
SimpleScrollGUI gui = new SimpleScrollGUI(width, height, items, ingredients.findIndicesOfMarkerAsArray(Marker.ITEM_LIST_SLOT));
ingredients.insertIntoGUI(gui);
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;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.GUI;
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.impl.pagedgui.BackItem;
import de.studiocode.invui.item.impl.pagedgui.ForwardItem;
import de.studiocode.invui.item.impl.controlitem.ControlItem;
import de.studiocode.invui.item.impl.controlitem.PageItem;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link GUI} with pages.
*
* @see PagedGUIBuilder
* @see GUIBuilder
* @see SimplePagedItemsGUI
* @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 int[] itemListSlots;
protected int currentPage;
private Item forwardItem;
private Item backItem;
public PagedGUI(int width, int height, boolean infinitePages, int... itemListSlots) {
super(width, height);
@ -30,9 +31,14 @@ public abstract class PagedGUI extends BaseGUI {
this.itemListSlots = itemListSlots;
}
public void setControlItems(int backItemSlot, BackItem backItem, int forwardItemSlot, ForwardItem forwardItem) {
setItem(backItemSlot, this.backItem = backItem);
setItem(forwardItemSlot, this.forwardItem = forwardItem);
@Override
public void addControlItem(int index, ControlItem<?> controlItem) {
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() {
@ -72,8 +78,7 @@ public abstract class PagedGUI extends BaseGUI {
}
private void updateControlItems() {
backItem.notifyWindows();
forwardItem.notifyWindows();
controlItems.forEach(Item::notifyWindows);
}
private void updatePageContent() {
@ -89,14 +94,6 @@ public abstract class PagedGUI extends BaseGUI {
return currentPage;
}
public Item getForwardItem() {
return forwardItem;
}
public Item getBackItem() {
return backItem;
}
public boolean hasInfinitePages() {
return infinitePages;
}

@ -1,8 +1,12 @@
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.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.List;
@ -12,7 +16,7 @@ import java.util.List;
*
* @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 boolean infiniteLines;
@ -21,12 +25,11 @@ public abstract class ScrollGUI extends BaseGUI {
protected int offset;
public ScrollGUI(int width, int height, boolean infiniteLines, int lineLength, int... itemListSlots) {
public ScrollGUI(int width, int height, boolean infiniteLines, int... itemListSlots) {
super(width, height);
this.infiniteLines = infiniteLines;
this.itemListSlots = itemListSlots;
this.lineLength = lineLength;
this.lineLength = SlotUtils.getLongestLineLength(itemListSlots, width);
if (lineLength == 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");
}
public void addControlItem(int index, Item item) {
controlItems.add(item);
setItem(index, item);
@Override
public void addControlItem(int index, ControlItem<?> controlItem) {
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) {

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

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

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

@ -2,36 +2,23 @@ package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.gui.SlotElement;
import de.studiocode.invui.gui.builder.TabGUIBuilder;
import de.studiocode.invui.item.impl.tabgui.TabItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import de.studiocode.invui.gui.builder.GUIBuilder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
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.
*
* @see TabGUIBuilder
* @see GUIBuilder
*/
public class SimpleTabGUI extends TabGUI {
private final List<GUI> tabs;
public SimpleTabGUI(int width, int height, LinkedHashMap<GUI, Function<TabGUI, ItemBuilder>> tabs,
int[] listSlots, int[] tabItemSlots) {
public SimpleTabGUI(int width, int height, List<GUI> tabs, int[] listSlots) {
super(width, height, tabs.size(), listSlots);
this.tabs = new ArrayList<>(tabs.keySet());
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);
}
this.tabs = tabs;
update();
}

@ -1,17 +1,19 @@
package de.studiocode.invui.gui.impl;
import de.studiocode.invui.gui.Controllable;
import de.studiocode.invui.gui.SlotElement;
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;
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[] listSlots;
private final Item[] tabItems;
private int currentTab;
@ -19,7 +21,6 @@ public abstract class TabGUI extends BaseGUI {
super(width, height);
this.tabAmount = tabAmount;
this.listSlots = listSlots;
this.tabItems = new Item[tabAmount];
}
public void showTab(int tab) {
@ -30,14 +31,26 @@ public abstract class TabGUI extends BaseGUI {
update();
}
public void setTabItem(int tab, int index, TabItem tabItem) {
tabItems[tab] = tabItem;
setItem(index, tabItem);
@Override
public void addControlItem(int index, ControlItem<?> controlItem) {
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() {
Arrays.stream(tabItems).forEach(Item::notifyWindows);
updateControlItems();
updateContent();
}
private void updateControlItems() {
controlItems.forEach(Item::notifyWindows);
}
private void updateContent() {
List<SlotElement> slotElements = getSlotElements(currentTab);
for (int i = 0; i < listSlots.length; 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.item.impl.FunctionItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@ -10,25 +9,27 @@ import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.HashMap;
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;
public ScrollItem(ScrollGUI scrollGUI, int scrollLeftClick, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(scrollGUI, builderFunction);
public ScrollItem(int scrollLeftClick, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(builderFunction);
scroll = new HashMap<>();
scroll.put(ClickType.LEFT, scrollLeftClick);
}
public ScrollItem(ScrollGUI scrollGUI, HashMap<ClickType, Integer> scroll, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(scrollGUI, builderFunction);
public ScrollItem(HashMap<ClickType, Integer> scroll, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(builderFunction);
this.scroll = scroll;
}
@Override
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.item.impl.FunctionItem;
import de.studiocode.invui.item.itembuilder.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@ -9,18 +8,21 @@ import org.bukkit.event.inventory.InventoryClickEvent;
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;
public TabItem(TabGUI tabGUI, int tab, Function<TabGUI, ItemBuilder> builderFunction) {
super(tabGUI, builderFunction);
public TabItem(int tab, Function<TabGUI, ItemBuilder> builderFunction) {
super(builderFunction);
this.tab = tab;
}
@Override
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;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class SlotUtils {
@ -75,6 +77,30 @@ public class SlotUtils {
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 {
HORIZONTAL,