diff --git a/src/main/java/de/studiocode/invui/gui/impl/BaseGUI.java b/src/main/java/de/studiocode/invui/gui/impl/BaseGUI.java index 4d4a52f..0b3b8e9 100644 --- a/src/main/java/de/studiocode/invui/gui/impl/BaseGUI.java +++ b/src/main/java/de/studiocode/invui/gui/impl/BaseGUI.java @@ -10,7 +10,7 @@ import de.studiocode.invui.util.SlotUtils; import de.studiocode.invui.virtualinventory.VirtualInventory; import org.jetbrains.annotations.NotNull; -import java.util.SortedSet; +import java.util.Set; /** * A subclass of {@link IndexedGUI} which contains all the @@ -79,7 +79,7 @@ public abstract class BaseGUI extends IndexedGUI { // filling methods - public void fill(@NotNull SortedSet slots, Item item, boolean replaceExisting) { + public void fill(@NotNull Set slots, Item item, boolean replaceExisting) { for (int slot : slots) { if (!replaceExisting && hasSlotElement(slot)) continue; setItem(slot, item); diff --git a/src/main/java/de/studiocode/invui/gui/impl/PagedGUI.java b/src/main/java/de/studiocode/invui/gui/impl/PagedGUI.java index 9e42333..e8cd13d 100644 --- a/src/main/java/de/studiocode/invui/gui/impl/PagedGUI.java +++ b/src/main/java/de/studiocode/invui/gui/impl/PagedGUI.java @@ -64,7 +64,8 @@ public abstract class PagedGUI extends BaseGUI { } private void correctPage() { - if (currentPage == 0) return; + if (currentPage == 0 || infinitePages) return; + int pageAmount = getPageAmount(); if (currentPage < 0) currentPage = 0; else if (currentPage >= pageAmount) currentPage = pageAmount - 1; diff --git a/src/main/java/de/studiocode/invui/gui/impl/ScrollGUI.java b/src/main/java/de/studiocode/invui/gui/impl/ScrollGUI.java new file mode 100644 index 0000000..2782ed4 --- /dev/null +++ b/src/main/java/de/studiocode/invui/gui/impl/ScrollGUI.java @@ -0,0 +1,120 @@ +package de.studiocode.invui.gui.impl; + +import de.studiocode.invui.gui.GUI; +import de.studiocode.invui.gui.SlotElement; +import de.studiocode.invui.item.Item; + +import java.util.ArrayList; +import java.util.List; + +/** + * A scrollable {@link GUI} + * + * @see SimpleScrollGUI + */ +public abstract class ScrollGUI extends BaseGUI { + + private final List controlItems = new ArrayList<>(); + private final boolean infiniteLines; + private final int lineLength; + private final int[] itemListSlots; + + protected int offset; + + + public ScrollGUI(int width, int height, boolean infiniteLines, int lineLength, int... itemListSlots) { + super(width, height); + this.infiniteLines = infiniteLines; + this.itemListSlots = itemListSlots; + this.lineLength = lineLength; + + if (lineLength == 0) + throw new IllegalArgumentException("Line length can't be 0"); + if (itemListSlots.length == 0) + throw new IllegalArgumentException("No item list slots provided"); + if (itemListSlots.length % lineLength != 0) + throw new IllegalArgumentException("itemListSlots has to be a multiple of lineLength"); + } + + public void addControlItem(int index, Item item) { + controlItems.add(item); + setItem(index, item); + } + + public void setCurrentLine(int line) { + this.offset = line * lineLength; + } + + public int getCurrentLine() { + return offset / lineLength; + } + + private int getMaxLineIndex() { + int maxLineIndex = (int) Math.ceil((double) getElementAmount() / (double) lineLength); + return Math.max(0, maxLineIndex - getLineAmount()); + } + + private int getLineAmount() { + return itemListSlots.length / lineLength; + } + + public boolean canScroll(int lines) { + if (lines == 0 || (infiniteLines && lines > 0)) return true; + + int line = getCurrentLine() + lines; + int maxLineAmount = getMaxLineIndex(); + return line >= 0 && line <= maxLineAmount; + } + + public void scroll(int lines) { + if (lines == 0) return; + + if (canScroll(lines)) { + setCurrentLine(getCurrentLine() + lines); + update(); + } else if (lines > 1) { + setCurrentLine(getMaxLineIndex()); + update(); + } else if (lines < -1) { + setCurrentLine(0); + update(); + } + + } + + protected void update() { + correctLine(); + updateControlItems(); + updateContent(); + } + + private void correctLine() { + if (offset == 0 || infiniteLines) return; + + if (offset < 0) { + offset = 0; + } else { + int currentLine = getCurrentLine(); + int maxLineIndex = getMaxLineIndex(); + if (currentLine >= maxLineIndex) setCurrentLine(maxLineIndex); + } + } + + private void updateControlItems() { + controlItems.forEach(Item::notifyWindows); + } + + private void updateContent() { + List slotElements = getElements(offset, itemListSlots.length + offset); + + for (int i = 0; i < itemListSlots.length; i++) { + if (slotElements.size() > i) setSlotElement(itemListSlots[i], slotElements.get(i)); + else remove(itemListSlots[i]); + } + } + + abstract protected int getElementAmount(); + + abstract protected List getElements(int from, int to); + +} diff --git a/src/main/java/de/studiocode/invui/gui/impl/SimpleScrollGUI.java b/src/main/java/de/studiocode/invui/gui/impl/SimpleScrollGUI.java new file mode 100644 index 0000000..f0a976c --- /dev/null +++ b/src/main/java/de/studiocode/invui/gui/impl/SimpleScrollGUI.java @@ -0,0 +1,37 @@ +package de.studiocode.invui.gui.impl; + +import de.studiocode.invui.gui.SlotElement; +import de.studiocode.invui.item.Item; + +import java.util.List; +import java.util.stream.Collectors; + +public class SimpleScrollGUI extends ScrollGUI { + + private List items; + + public SimpleScrollGUI(int width, int height, List items, int lineLength, int... itemListSlots) { + super(width, height, false, lineLength, itemListSlots); + this.items = items; + + update(); + } + + public void setItems(List items) { + this.items = items; + update(); + } + + @Override + protected int getElementAmount() { + return items.size(); + } + + @Override + protected List getElements(int from, int to) { + return items.subList(from, Math.min(items.size(), to)).stream() + .map(SlotElement.ItemSlotElement::new) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/de/studiocode/invui/item/impl/scrollgui/ScrollItem.java b/src/main/java/de/studiocode/invui/item/impl/scrollgui/ScrollItem.java new file mode 100644 index 0000000..9b134a8 --- /dev/null +++ b/src/main/java/de/studiocode/invui/item/impl/scrollgui/ScrollItem.java @@ -0,0 +1,34 @@ +package de.studiocode.invui.item.impl.scrollgui; + +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; +import org.bukkit.event.inventory.InventoryClickEvent; + +import java.util.HashMap; +import java.util.function.Function; + +public class ScrollItem extends FunctionItem { + + private final HashMap scroll; + + public ScrollItem(ScrollGUI scrollGUI, int scrollLeftClick, Function builderFunction) { + super(scrollGUI, builderFunction); + + scroll = new HashMap<>(); + scroll.put(ClickType.LEFT, scrollLeftClick); + } + + public ScrollItem(ScrollGUI scrollGUI, HashMap scroll, Function builderFunction) { + super(scrollGUI, builderFunction); + this.scroll = scroll; + } + + @Override + public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) { + if (scroll.containsKey(clickType)) getT().scroll(scroll.get(clickType)); + } + +} diff --git a/src/main/java/de/studiocode/invui/util/Point2D.java b/src/main/java/de/studiocode/invui/util/Point2D.java new file mode 100644 index 0000000..a228c04 --- /dev/null +++ b/src/main/java/de/studiocode/invui/util/Point2D.java @@ -0,0 +1,21 @@ +package de.studiocode.invui.util; + +public class Point2D { + + private int x; + private int y; + + public Point2D(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + +} diff --git a/src/main/java/de/studiocode/invui/util/SlotUtils.java b/src/main/java/de/studiocode/invui/util/SlotUtils.java index 0a6ad75..059ce62 100644 --- a/src/main/java/de/studiocode/invui/util/SlotUtils.java +++ b/src/main/java/de/studiocode/invui/util/SlotUtils.java @@ -1,24 +1,24 @@ package de.studiocode.invui.util; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.LinkedHashSet; +import java.util.Set; public class SlotUtils { - public static SortedSet getSlotsRow(int row, int width) { - SortedSet slots = new TreeSet<>(); + public static Set getSlotsRow(int row, int width) { + Set slots = new LinkedHashSet<>(); for (int x = 0; x < width; x++) slots.add(convertToIndex(x, row, width)); return slots; } - public static SortedSet getSlotsColumn(int column, int width, int height) { - SortedSet slots = new TreeSet<>(); + public static Set getSlotsColumn(int column, int width, int height) { + Set slots = new LinkedHashSet<>(); for (int y = 0; y < height; y++) slots.add(convertToIndex(column, y, width)); return slots; } - public static SortedSet getSlotsBorders(int width, int height) { - SortedSet slots = new TreeSet<>(); + public static Set getSlotsBorders(int width, int height) { + Set slots = new LinkedHashSet<>(); if (height > 0) slots.addAll(getSlotsRow(0, width)); if (height - 1 > 0) slots.addAll(getSlotsRow(height - 1, width)); if (width > 0) slots.addAll(getSlotsColumn(0, width, height)); @@ -26,21 +26,45 @@ public class SlotUtils { return slots; } - public static SortedSet getSlotsRect(int x, int y, int width, int height, int frameWidth) { - SortedSet slots = new TreeSet<>(); - for (int y1 = y; y1 < height + y; y1++) { - for (int x1 = x; x1 < width + x; x1++) { - slots.add(convertToIndex(x1, y1, frameWidth)); - } + public static Set getSlotsRect(int x, int y, int width, int height, int frameWidth) { + return getSlotsRect(Order.HORIZONTAL, x, y, width, height, frameWidth); + } + + public static Set getSlotsRect(Order order, int x, int y, int width, int height, int frameWidth) { + Set slots = new LinkedHashSet<>(); + + switch (order) { + case HORIZONTAL: + for (int y1 = y; y1 < height + y; y1++) { + for (int x1 = x; x1 < width + x; x1++) { + slots.add(convertToIndex(x1, y1, frameWidth)); + } + } + break; + + case VERTICAL: + for (int x1 = x; x1 < width + x; x1++) { + for (int y1 = y; y1 < height + y; y1++) { + slots.add(convertToIndex(x1, y1, frameWidth)); + } + } } return slots; } + public static int convertToIndex(Point2D point, int width) { + return convertToIndex(point.getX(), point.getY(), width); + } + public static int convertToIndex(int x, int y, int width) { return y * width + x; } + public static Point2D convertFromIndex(int index, int width) { + return new Point2D(index % width, index / width); + } + public static int translatePlayerInvToGui(int slot) { if (slot > 8) return slot - 9; else return slot + 27; @@ -51,4 +75,11 @@ public class SlotUtils { else return slot + 9; } + public enum Order { + + HORIZONTAL, + VERTICAL + + } + } diff --git a/src/main/java/de/studiocode/invui/window/impl/single/SimpleWindow.java b/src/main/java/de/studiocode/invui/window/impl/single/SimpleWindow.java index 4a24f08..75dff4b 100644 --- a/src/main/java/de/studiocode/invui/window/impl/single/SimpleWindow.java +++ b/src/main/java/de/studiocode/invui/window/impl/single/SimpleWindow.java @@ -12,8 +12,16 @@ public class SimpleWindow extends SingleWindow { super(viewerUUID, gui, InventoryUtils.createMatchingInventory(gui, title), true, closeable, closeOnEvent); } + public SimpleWindow(UUID viewerUUID, String title, GUI gui) { + this(viewerUUID, title, gui, true, true); + } + public SimpleWindow(Player player, String title, GUI gui, boolean closeable, boolean closeOnEvent) { this(player.getUniqueId(), title, gui, closeable, closeOnEvent); } + public SimpleWindow(Player player, String title, GUI gui) { + this(player, title, gui, true, true); + } + }