Improved Gui- and Window builders

This commit is contained in:
NichtStudioCode 2023-02-26 15:29:57 +01:00
parent b86f79d851
commit 4f6dee6861
60 changed files with 1899 additions and 1532 deletions

@ -1,11 +0,0 @@
@file:Suppress("PackageDirectoryMismatch")
package xyz.xenondevs.invui.gui.builder
import xyz.xenondevs.invui.gui.Gui
fun <G : Gui, B : GuiBuilder<G>> GuiType<G, B>.create(builderConsumer: B.() -> Unit): G {
val builder = builder()
builder.builderConsumer()
return builder.build()
}

@ -9,4 +9,4 @@ import xyz.xenondevs.invui.util.ComponentUtils
/** /**
* Sets the lore of the item stack. * Sets the lore of the item stack.
*/ */
fun <T> AbstractItemBuilder<T>.setLore(lore: List<Array<BaseComponent>>): T = setLore(lore.map { BaseComponentWrapper(ComponentUtils.withoutPreFormatting(*it)) }) fun <T : AbstractItemBuilder<T>> T.setLore(lore: List<Array<BaseComponent>>): T = setLore(lore.map { BaseComponentWrapper(ComponentUtils.withoutPreFormatting(*it)) })

@ -1,11 +0,0 @@
@file:Suppress("PackageDirectoryMismatch")
package xyz.xenondevs.invui.window.builder
import xyz.xenondevs.invui.window.Window
fun <W : Window, B : WindowBuilder<W>> WindowType<W, B>.create(builderConsumer: B.() -> Unit): W {
val builder = builder()
builder.builderConsumer()
return builder.build()
}

@ -8,14 +8,14 @@ import xyz.xenondevs.inventoryaccess.component.AdventureComponentWrapper
/** /**
* Sets the display name of the item stack. * Sets the display name of the item stack.
*/ */
fun <T> AbstractItemBuilder<T>.setDisplayName(displayName: Component): T = setDisplayName(AdventureComponentWrapper(displayName)) fun <T : AbstractItemBuilder<T>> T.setDisplayName(displayName: Component): T = setDisplayName(AdventureComponentWrapper(displayName))
/** /**
* Sets the lore the item stack. * Sets the lore the item stack.
*/ */
fun <T> AbstractItemBuilder<T>.setLore(lore: List<Component>): T = setLore(lore.map { AdventureComponentWrapper(it) }) fun <T : AbstractItemBuilder<T>> T.setLore(lore: List<Component>): T = setLore(lore.map { AdventureComponentWrapper(it) })
/** /**
* Adds lore lines to the item stack. * Adds lore lines to the item stack.
*/ */
fun <T> AbstractItemBuilder<T>.addLoreLines(vararg components: Component): T = addLoreLines(*components.map { AdventureComponentWrapper(it) }.toTypedArray()) fun <T : AbstractItemBuilder<T>> T.addLoreLines(vararg components: Component): T = addLoreLines(*components.map { AdventureComponentWrapper(it) }.toTypedArray())

@ -3,10 +3,15 @@
package xyz.xenondevs.invui.window.type.context package xyz.xenondevs.invui.window.type.context
import net.kyori.adventure.text.Component import net.kyori.adventure.text.Component
import org.jetbrains.annotations.Contract
import xyz.xenondevs.inventoryaccess.component.AdventureComponentWrapper import xyz.xenondevs.inventoryaccess.component.AdventureComponentWrapper
import xyz.xenondevs.invui.window.builder.AbstractWindowBuilder import xyz.xenondevs.invui.window.Window
/** /**
* Sets the title of the window. * Sets the title of the window.
*
* @param title the new title
* @return This Window Builder
*/ */
fun AbstractWindowBuilder<*, *, *>.setTitle(title: Component) = setTitle(AdventureComponentWrapper(title)) @Contract("_ -> this")
fun <B : Window.Builder<*, *, B>> B.setTitle(title: Component): B = setTitle(AdventureComponentWrapper(title))

@ -10,9 +10,11 @@ import org.bukkit.inventory.PlayerInventory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.animation.Animation; import xyz.xenondevs.invui.animation.Animation;
import xyz.xenondevs.invui.gui.structure.Marker;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.Item; import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.item.ItemProvider; import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.ItemWrapper;
import xyz.xenondevs.invui.item.impl.controlitem.ControlItem; import xyz.xenondevs.invui.item.impl.controlitem.ControlItem;
import xyz.xenondevs.invui.util.ArrayUtils; import xyz.xenondevs.invui.util.ArrayUtils;
import xyz.xenondevs.invui.util.InventoryUtils; import xyz.xenondevs.invui.util.InventoryUtils;
@ -24,7 +26,9 @@ import xyz.xenondevs.invui.virtualinventory.event.UpdateReason;
import xyz.xenondevs.invui.window.*; import xyz.xenondevs.invui.window.*;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public abstract class AbstractGui implements Gui, GuiParent { public abstract class AbstractGui implements Gui, GuiParent {
@ -682,4 +686,135 @@ public abstract class AbstractGui implements Gui, GuiParent {
} }
// endregion // endregion
@SuppressWarnings("unchecked")
public static abstract class AbstractBuilder<G extends Gui, S extends Gui.Builder<G, S>> implements Gui.Builder<G, S> {
protected Structure structure;
protected ItemProvider background;
protected List<Consumer<Gui>> modifiers;
@Override
public S setStructure(int width, int height, @NotNull String structureData) {
structure = new Structure(width, height, structureData);
return (S) this;
}
@Override
public S setStructure(@NotNull String... structureData) {
structure = new Structure(structureData);
return (S) this;
}
@Override
public S setStructure(@NotNull Structure structure) {
this.structure = structure;
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull ItemStack itemStack) {
structure.addIngredient(key, itemStack);
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull ItemProvider itemProvider) {
structure.addIngredient(key, itemProvider);
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull Item item) {
structure.addIngredient(key, item);
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull VirtualInventory inventory) {
structure.addIngredient(key, inventory);
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull VirtualInventory inventory, @Nullable ItemProvider background) {
structure.addIngredient(key, inventory, background);
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull SlotElement element) {
structure.addIngredient(key, element);
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull Marker marker) {
structure.addIngredient(key, marker);
return (S) this;
}
@Override
public S addIngredient(char key, @NotNull Supplier<? extends Item> itemSupplier) {
structure.addIngredient(key, itemSupplier);
return (S) this;
}
@Override
public S addIngredientElementSupplier(char key, @NotNull Supplier<? extends SlotElement> elementSupplier) {
structure.addIngredientElementSupplier(key, elementSupplier);
return (S) this;
}
@Override
public S setBackground(@NotNull ItemProvider itemProvider) {
background = itemProvider;
return (S) this;
}
@Override
public S setBackground(@NotNull ItemStack itemStack) {
background = new ItemWrapper(itemStack);
return (S) this;
}
@Override
public S addModifier(@NotNull Consumer<@NotNull Gui> modifier) {
if (modifiers == null)
modifiers = new ArrayList<>();
modifiers.add(modifier);
return (S) this;
}
@Override
public S setModifiers(@NotNull List<@NotNull Consumer<@NotNull Gui>> modifiers) {
this.modifiers = modifiers;
return (S) this;
}
protected void applyModifiers(@NotNull G gui) {
if (background != null) {
gui.setBackground(background);
}
if (modifiers != null) {
modifiers.forEach(modifier -> modifier.accept(gui));
}
}
@SuppressWarnings("unchecked")
@Override
public @NotNull S clone() {
try {
var clone = (AbstractBuilder<G, S>) super.clone();
clone.structure = structure.clone();
if (modifiers != null)
clone.modifiers = new ArrayList<>(modifiers);
return (S) clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
} }

@ -2,9 +2,6 @@ package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.builder.GuiType;
import xyz.xenondevs.invui.gui.impl.PagedItemsGuiImpl;
import xyz.xenondevs.invui.gui.impl.PagedNestedGuiImpl;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import java.util.ArrayList; import java.util.ArrayList;
@ -14,7 +11,6 @@ import java.util.function.BiConsumer;
/** /**
* A {@link Gui} with pages. * A {@link Gui} with pages.
* *
* @see GuiType
* @see PagedItemsGuiImpl * @see PagedItemsGuiImpl
* @see PagedNestedGuiImpl * @see PagedNestedGuiImpl
*/ */
@ -135,4 +131,58 @@ public abstract class AbstractPagedGui<C> extends AbstractGui implements PagedGu
protected abstract List<SlotElement> getPageElements(int page); protected abstract List<SlotElement> getPageElements(int page);
public static abstract class AbstractBuilder<C>
extends AbstractGui.AbstractBuilder<PagedGui<C>, PagedGui.Builder<C>>
implements PagedGui.Builder<C>
{
protected List<C> content;
protected List<BiConsumer<Integer, Integer>> pageChangeHandlers;
@Override
public PagedGui.Builder<C> setContent(@NotNull List<@NotNull C> content) {
this.content = content;
return this;
}
@Override
public PagedGui.Builder<C> addContent(@NotNull C content) {
if (this.content == null)
this.content = new ArrayList<>();
this.content.add(content);
return this;
}
@Override
public PagedGui.Builder<C> setPageChangeHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers) {
pageChangeHandlers = handlers;
return this;
}
@Override
public PagedGui.Builder<C> addPageChangeHandler(@NotNull BiConsumer<Integer, Integer> handler) {
if (pageChangeHandlers == null)
pageChangeHandlers = new ArrayList<>(1);
pageChangeHandlers.add(handler);
return this;
}
@Override
protected void applyModifiers(@NotNull PagedGui<C> gui) {
super.applyModifiers(gui);
gui.setPageChangeHandlers(pageChangeHandlers);
}
@Override
public @NotNull PagedGui.Builder<C> clone() {
var clone = (AbstractBuilder<C>) super.clone();
clone.content = new ArrayList<>(content);
clone.pageChangeHandlers = new ArrayList<>(pageChangeHandlers);
return clone;
}
}
} }

@ -1,8 +1,6 @@
package xyz.xenondevs.invui.gui; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.impl.ScrollItemsGuiImpl;
import xyz.xenondevs.invui.gui.impl.ScrollNestedGuiImpl;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.util.SlotUtils; import xyz.xenondevs.invui.util.SlotUtils;
@ -134,4 +132,58 @@ public abstract class AbstractScrollGui<C> extends AbstractGui implements Scroll
protected abstract List<? extends SlotElement> getElements(int from, int to); protected abstract List<? extends SlotElement> getElements(int from, int to);
public abstract static class AbstractBuilder<C>
extends AbstractGui.AbstractBuilder<ScrollGui<C>, ScrollGui.Builder<C>>
implements ScrollGui.Builder<C>
{
protected List<C> content;
protected List<BiConsumer<Integer, Integer>> scrollHandlers;
@Override
public ScrollGui.Builder<C> setContent(@NotNull List<@NotNull C> content) {
this.content = content;
return this;
}
@Override
public ScrollGui.Builder<C> addContent(@NotNull C content) {
if (this.content == null)
this.content = new ArrayList<>();
this.content.add(content);
return this;
}
@Override
public ScrollGui.Builder<C> setScrollHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers) {
scrollHandlers = handlers;
return this;
}
@Override
public ScrollGui.Builder<C> addScrollHandler(@NotNull BiConsumer<Integer, Integer> handler) {
if (scrollHandlers == null)
scrollHandlers = new ArrayList<>(1);
scrollHandlers.add(handler);
return this;
}
@Override
protected void applyModifiers(@NotNull ScrollGui<C> gui) {
super.applyModifiers(gui);
gui.setScrollHandlers(scrollHandlers);
}
@Override
public @NotNull ScrollGui.Builder<C> clone() {
var clone = (AbstractBuilder<C>) super.clone();
clone.content = new ArrayList<>(content);
clone.scrollHandlers = new ArrayList<>(scrollHandlers);
return clone;
}
}
} }

@ -96,5 +96,58 @@ public abstract class AbstractTabGui extends AbstractGui implements TabGui {
protected abstract List<SlotElement> getSlotElements(int tab); protected abstract List<SlotElement> getSlotElements(int tab);
public static abstract class AbstractBuilder
extends AbstractGui.AbstractBuilder<TabGui, TabGui.Builder>
implements TabGui.Builder
{
protected List<Gui> tabs;
protected List<BiConsumer<Integer, Integer>> tabChangeHandlers;
@Override
public TabGui.Builder setTabs(@NotNull List<@Nullable Gui> tabs) {
this.tabs = tabs;
return this;
}
@Override
public TabGui.Builder addTab(@Nullable Gui tab) {
if (this.tabs == null)
this.tabs = new ArrayList<>();
this.tabs.add(tab);
return this;
}
@Override
public TabGui.Builder addTabChangeHandler(@NotNull BiConsumer<Integer, Integer> handler) {
if (tabChangeHandlers == null)
tabChangeHandlers = new ArrayList<>(1);
tabChangeHandlers.add(handler);
return this;
}
@Override
public TabGui.Builder setTabChangeHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers) {
tabChangeHandlers = handlers;
return this;
}
@Override
protected void applyModifiers(@NotNull TabGui gui) {
super.applyModifiers(gui);
gui.setTabChangeHandlers(tabChangeHandlers);
}
@Override
public @NotNull TabGui.Builder clone() {
var clone = (AbstractBuilder) super.clone();
clone.tabs = new ArrayList<>(tabs);
clone.tabChangeHandlers = new ArrayList<>(tabChangeHandlers);
return clone;
}
}
} }

@ -2,11 +2,12 @@ package xyz.xenondevs.invui.gui;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.animation.Animation; import xyz.xenondevs.invui.animation.Animation;
import xyz.xenondevs.invui.gui.builder.GuiType; import xyz.xenondevs.invui.gui.structure.Marker;
import xyz.xenondevs.invui.gui.impl.NormalGuiImpl;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.Item; import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.item.ItemProvider; import xyz.xenondevs.invui.item.ItemProvider;
@ -16,7 +17,9 @@ import xyz.xenondevs.invui.window.WindowManager;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier;
/** /**
* A Gui is a container for width * height {@link SlotElement SlotElements}.<br> * A Gui is a container for width * height {@link SlotElement SlotElements}.<br>
@ -28,15 +31,33 @@ import java.util.function.Predicate;
* In order to create an {@link Inventory} which is visible * In order to create an {@link Inventory} which is visible
* to players, you will need to use a {@link Window}. * to players, you will need to use a {@link Window}.
* *
* @see GuiType * @see PagedGui
* @see AbstractGui * @see ScrollGui
* @see AbstractPagedGui * @see TabGui
* @see AbstractScrollGui
* @see AbstractTabGui
*/ */
@SuppressWarnings("deprecation")
public interface Gui { public interface Gui {
/**
* Creates a new {@link Builder.Normal Gui Builder} for a normal {@link Gui}.
*
* @return The new {@link Builder.Normal Gui Builder}.
*/
static @NotNull Builder.Normal normal() {
return new NormalGuiImpl.Builder();
}
/**
* Creates a new normal {@link Gui} after configuring a {@link Builder.Normal Gui Builder} with the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder.Normal Gui Builder}.
* @return The created {@link Gui}.
*/
static @NotNull Gui normal(@NotNull Consumer<Builder.@NotNull Normal> consumer) {
Builder.Normal builder = normal();
consumer.accept(builder);
return builder.build();
}
/** /**
* Creates a new empty {@link Gui}. * Creates a new empty {@link Gui}.
* *
@ -356,4 +377,195 @@ public interface Gui {
//</editor-fold> //</editor-fold>
/**
* A {@link Gui} builder.
*
* @param <G> The type of the {@link Gui}
* @param <S> The type of the builder
*/
interface Builder<G extends Gui, S extends Builder<G, S>> extends Cloneable {
/**
* Sets the {@link Structure} of the {@link Gui}.
*
* @param structure The {@link Structure} of the {@link Gui}
* @return This {@link Builder}
*/
@Contract("_ -> this")
S setStructure(@NotNull Structure structure);
/**
* Sets the {@link Structure} of the {@link Gui} using the given structure data Strings.
* Each String is interpreted as a row of the {@link Gui}. All Strings must have the same length.
*
* @param structureData The structure data
* @return This {@link Builder Gui Builder}
*/
@Contract("_ -> this")
S setStructure(@NotNull String... structureData);
/**
* Sets the {@link Structure} of the {@link Gui} using the given structure data, width and height.
*
* @param width The width of the {@link Gui}
* @param height The height of the {@link Gui}
* @param structureData The structure data
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _, _, -> this")
S setStructure(int width, int height, @NotNull String structureData);
/**
* Adds an {@link ItemStack} ingredient under the given key.
*
* @param key The key
* @param itemStack The {@link ItemStack}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredient(char key, @NotNull ItemStack itemStack);
/**
* Adds an {@link ItemProvider} ingredient under the given key.
*
* @param key The key
* @param itemProvider The {@link ItemProvider}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredient(char key, @NotNull ItemProvider itemProvider);
/**
* Adds an {@link Item} ingredient under the given key.
*
* @param key The key
* @param item The {@link Item}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredient(char key, @NotNull Item item);
/**
* Adds an {@link VirtualInventory} ingredient under the given key.
*
* @param key The key
* @param inventory The {@link VirtualInventory}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredient(char key, @NotNull VirtualInventory inventory);
/**
* Adds an {@link VirtualInventory} ingredient under the given key.
*
* @param key The key
* @param inventory The {@link VirtualInventory}
* @param background The {@link ItemProvider} for empty slots of the {@link VirtualInventory}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _, _ -> this")
S addIngredient(char key, @NotNull VirtualInventory inventory, @Nullable ItemProvider background);
/**
* Adds a {@link SlotElement} ingredient under the given key.
*
* @param key The key
* @param element The {@link SlotElement}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredient(char key, @NotNull SlotElement element);
/**
* Adds a {@link Marker} ingredient under the given key.
*
* @param key The key
* @param marker The {@link Marker}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredient(char key, @NotNull Marker marker);
/**
* Adds a {@link Supplier} of {@link Item Items} ingredient under the given key.
*
* @param key The key
* @param itemSupplier The {@link Supplier} of {@link Item Items}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredient(char key, @NotNull Supplier<? extends Item> itemSupplier);
/**
* Adds a {@link Supplier} of {@link SlotElement SlotElements} ingredient under the given key.
*
* @param key The key
* @param elementSupplier The {@link Supplier} of {@link SlotElement SlotElements}
* @return This {@link Builder Gui Builder}
*/
@Contract("_, _ -> this")
S addIngredientElementSupplier(char key, @NotNull Supplier<? extends SlotElement> elementSupplier);
/**
* Sets the background of the {@link Gui}.
*
* @param itemProvider The {@link ItemProvider} for the background
* @return This {@link Builder Gui Builder}
*/
@Contract("_ -> this")
S setBackground(@NotNull ItemProvider itemProvider);
/**
* Sets the background of the {@link Gui}.
*
* @param itemStack The {@link ItemStack} for the background
* @return This {@link Builder Gui Builder}
*/
@Contract("_ -> this")
S setBackground(@NotNull ItemStack itemStack);
/**
* Sets the background of the {@link Gui}.
*
* @param modifier The {@link Consumer} for the background
* @return This {@link Builder Gui Builder}
*/
@Contract("_ -> this")
S addModifier(@NotNull Consumer<@NotNull Gui> modifier);
/**
* Sets the background of the {@link Gui}.
*
* @param modifiers The {@link Consumer Consumers} for the background
* @return This {@link Builder Gui Builder}
*/
@Contract("_ -> this")
S setModifiers(@NotNull List<@NotNull Consumer<@NotNull Gui>> modifiers);
/**
* Builds the {@link Gui}.
*
* @return The {@link Gui}
*/
@Contract("-> new")
@NotNull G build();
/**
* Clones the Gui Builder.
*
* @return The cloned Gui Builder
*/
@Contract("-> new")
@NotNull S clone();
/**
* A normal {@link Gui} builder.
*
* @see PagedGui.Builder
* @see ScrollGui.Builder
* @see TabGui.Builder
*/
interface Normal extends Builder<Gui, Normal> {}
}
} }

@ -1,24 +1,19 @@
package xyz.xenondevs.invui.gui.impl; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
/** /**
* A normal {@link Gui} without any special features. * A normal {@link Gui} without any special features.
*/ */
@SuppressWarnings("DeprecatedIsStillUsed") final class NormalGuiImpl extends AbstractGui {
public final class NormalGuiImpl extends AbstractGui {
/** /**
* Creates a new {@link NormalGuiImpl}. * Creates a new {@link NormalGuiImpl}.
* *
* @param width The width of this Gui. * @param width The width of this Gui.
* @param height The height of this Gui. * @param height The height of this Gui.
* @deprecated Use {@link Gui#empty(int, int)} instead.
*/ */
@Deprecated
public NormalGuiImpl(int width, int height) { public NormalGuiImpl(int width, int height) {
super(width, height); super(width, height);
} }
@ -27,12 +22,24 @@ public final class NormalGuiImpl extends AbstractGui {
* Creates a new {@link NormalGuiImpl}. * Creates a new {@link NormalGuiImpl}.
* *
* @param structure The {@link Structure} to use. * @param structure The {@link Structure} to use.
* @deprecated Use {@link Gui#of(Structure)} instead.
*/ */
@Deprecated
public NormalGuiImpl(@NotNull Structure structure) { public NormalGuiImpl(@NotNull Structure structure) {
super(structure.getWidth(), structure.getHeight()); super(structure.getWidth(), structure.getHeight());
applyStructure(structure); applyStructure(structure);
} }
public static class Builder extends AbstractBuilder<Gui, Gui.Builder.Normal> implements Gui.Builder.Normal {
@Override
public @NotNull Gui build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new NormalGuiImpl(structure);
applyModifiers(gui);
return gui;
}
}
} }

@ -1,18 +1,43 @@
package xyz.xenondevs.invui.gui; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.impl.PagedItemsGuiImpl;
import xyz.xenondevs.invui.gui.impl.PagedNestedGuiImpl;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.Item; import xyz.xenondevs.invui.item.Item;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
@SuppressWarnings("deprecation") /**
* A {@link Gui} that can display multiple pages of content.
*
* @param <C> The content type
*/
public interface PagedGui<C> extends Gui { public interface PagedGui<C> extends Gui {
/**
* Creates a new {@link Builder Gui Builder} for a {@link PagedGui} that uses {@link Item Items} as content.
*
* @return The new {@link Builder Gui Builder}.
*/
static @NotNull Builder<@NotNull Item> items() {
return new PagedItemsGuiImpl.Builder();
}
/**
* Creates a new {@link PagedGui} after configuring a {@link Builder Gui Builder} using the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder Gui Builder}.
* @return The created {@link PagedGui}.
*/
static @NotNull PagedGui<@NotNull Item> items(@NotNull Consumer<@NotNull Builder<@NotNull Item>> consumer) {
Builder<@NotNull Item> builder = items();
consumer.accept(builder);
return builder.build();
}
/** /**
* Creates a new {@link PagedGui}. * Creates a new {@link PagedGui}.
* *
@ -22,7 +47,7 @@ public interface PagedGui<C> extends Gui {
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @return The created {@link PagedGui}. * @return The created {@link PagedGui}.
*/ */
static @NotNull PagedGui<Item> ofItems(int width, int height, @NotNull List<@NotNull Item> items, int... contentListSlots) { static @NotNull PagedGui<@NotNull Item> ofItems(int width, int height, @NotNull List<@NotNull Item> items, int... contentListSlots) {
return new PagedItemsGuiImpl(width, height, items, contentListSlots); return new PagedItemsGuiImpl(width, height, items, contentListSlots);
} }
@ -33,10 +58,31 @@ public interface PagedGui<C> extends Gui {
* @param items The {@link Item Items} to use as in pages. * @param items The {@link Item Items} to use as in pages.
* @return The created {@link PagedGui}. * @return The created {@link PagedGui}.
*/ */
static @NotNull PagedGui<Item> ofItems(Structure structure, @NotNull List<@NotNull Item> items) { static @NotNull PagedGui<@NotNull Item> ofItems(@NotNull Structure structure, @NotNull List<@NotNull Item> items) {
return new PagedItemsGuiImpl(items, structure); return new PagedItemsGuiImpl(items, structure);
} }
/**
* Creates a new {@link Builder Gui Builder} for a {@link PagedGui} that uses {@link Gui Guis} as content.
*
* @return The new {@link Builder Gui Builder}.
*/
static @NotNull Builder<@NotNull Gui> guis() {
return new PagedNestedGuiImpl.Builder();
}
/**
* Creates a new {@link PagedGui} after configuring a {@link Builder Gui Builder} using the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder Gui Builder}.
* @return The created {@link PagedGui}.
*/
static @NotNull PagedGui<@NotNull Gui> guis(@NotNull Consumer<@NotNull Builder<@NotNull Gui>> consumer) {
Builder<@NotNull Gui> builder = guis();
consumer.accept(builder);
return builder.build();
}
/** /**
* Creates a new {@link PagedGui}. * Creates a new {@link PagedGui}.
* *
@ -46,7 +92,7 @@ public interface PagedGui<C> extends Gui {
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @return The created {@link PagedGui}. * @return The created {@link PagedGui}.
*/ */
static @NotNull PagedGui<Gui> ofGuis(int width, int height, @NotNull List<@NotNull Gui> guis, int... contentListSlots) { static @NotNull PagedGui<@NotNull Gui> ofGuis(int width, int height, @NotNull List<@NotNull Gui> guis, int... contentListSlots) {
return new PagedNestedGuiImpl(width, height, guis, contentListSlots); return new PagedNestedGuiImpl(width, height, guis, contentListSlots);
} }
@ -57,7 +103,7 @@ public interface PagedGui<C> extends Gui {
* @param guis The {@link Gui Guis} to use as pages. * @param guis The {@link Gui Guis} to use as pages.
* @return The created {@link PagedGui}. * @return The created {@link PagedGui}.
*/ */
static @NotNull PagedGui<Gui> ofGuis(Structure structure, @NotNull List<@NotNull Gui> guis) { static @NotNull PagedGui<@NotNull Gui> ofGuis(@NotNull Structure structure, @NotNull List<@NotNull Gui> guis) {
return new PagedNestedGuiImpl(guis, structure); return new PagedNestedGuiImpl(guis, structure);
} }
@ -155,4 +201,49 @@ public interface PagedGui<C> extends Gui {
*/ */
void removePageChangeHandler(@NotNull BiConsumer<Integer, Integer> handler); void removePageChangeHandler(@NotNull BiConsumer<Integer, Integer> handler);
/**
* A {@link PagedGui} builder.
*
* @param <C> The content type.
*/
interface Builder<C> extends Gui.Builder<PagedGui<C>, Builder<C>> {
/**
* Sets the content of the {@link PagedGui} for all pages.
*
* @param content The content to set.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> setContent(@NotNull List<@NotNull C> content);
/**
* Adds content to the {@link PagedGui}.
*
* @param content The content to add.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> addContent(@NotNull C content);
/**
* Sets the page change handlers of the {@link PagedGui}.
*
* @param handlers The page change handlers to set.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> setPageChangeHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers);
/**
* Adds a page change handler to the {@link PagedGui}.
*
* @param handler The page change handler to add.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> addPageChangeHandler(@NotNull BiConsumer<Integer, Integer> handler);
}
} }

@ -1,11 +1,7 @@
package xyz.xenondevs.invui.gui.impl; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.AbstractPagedGui;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.gui.builder.GuiType;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.Item; import xyz.xenondevs.invui.item.Item;
@ -17,11 +13,9 @@ import java.util.stream.Collectors;
/** /**
* A {@link AbstractPagedGui} that is filled with {@link Item Items}. * A {@link AbstractPagedGui} that is filled with {@link Item Items}.
* *
* @see GuiType
* @see PagedNestedGuiImpl * @see PagedNestedGuiImpl
*/ */
@SuppressWarnings("DeprecatedIsStillUsed") final class PagedItemsGuiImpl extends AbstractPagedGui<Item> {
public final class PagedItemsGuiImpl extends AbstractPagedGui<Item> {
private List<Item> items; private List<Item> items;
private List<BiConsumer<Integer, Integer>> pageChangeHandlers; private List<BiConsumer<Integer, Integer>> pageChangeHandlers;
@ -33,9 +27,7 @@ public final class PagedItemsGuiImpl extends AbstractPagedGui<Item> {
* @param height The height of this Gui. * @param height The height of this Gui.
* @param items The {@link Item Items} to use as pages. * @param items The {@link Item Items} to use as pages.
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @deprecated Use {@link PagedGui#ofItems(int, int, List, int...)} instead.
*/ */
@Deprecated
public PagedItemsGuiImpl(int width, int height, @Nullable List<@NotNull Item> items, int... contentListSlots) { public PagedItemsGuiImpl(int width, int height, @Nullable List<@NotNull Item> items, int... contentListSlots) {
super(width, height, false, contentListSlots); super(width, height, false, contentListSlots);
setContent(items); setContent(items);
@ -46,9 +38,7 @@ public final class PagedItemsGuiImpl extends AbstractPagedGui<Item> {
* *
* @param items The {@link Item Items} to use as pages. * @param items The {@link Item Items} to use as pages.
* @param structure The {@link Structure} to use. * @param structure The {@link Structure} to use.
* @deprecated Use {@link PagedGui#ofItems(Structure, List)} instead.
*/ */
@Deprecated
public PagedItemsGuiImpl(@Nullable List<@NotNull Item> items, @NotNull Structure structure) { public PagedItemsGuiImpl(@Nullable List<@NotNull Item> items, @NotNull Structure structure) {
super(structure.getWidth(), structure.getHeight(), false, structure); super(structure.getWidth(), structure.getHeight(), false, structure);
setContent(items); setContent(items);
@ -74,4 +64,18 @@ public final class PagedItemsGuiImpl extends AbstractPagedGui<Item> {
return items.subList(from, to).stream().map(SlotElement.ItemSlotElement::new).collect(Collectors.toList()); return items.subList(from, to).stream().map(SlotElement.ItemSlotElement::new).collect(Collectors.toList());
} }
public static final class Builder extends AbstractBuilder<Item> {
@Override
public @NotNull PagedGui<Item> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new PagedItemsGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
}
} }

@ -1,12 +1,7 @@
package xyz.xenondevs.invui.gui.impl; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.AbstractPagedGui;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.gui.builder.GuiType;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import java.util.ArrayList; import java.util.ArrayList;
@ -17,11 +12,9 @@ import java.util.stream.IntStream;
/** /**
* A {@link AbstractPagedGui} where every page is its own {@link Gui}. * A {@link AbstractPagedGui} where every page is its own {@link Gui}.
* *
* @see GuiType
* @see PagedItemsGuiImpl * @see PagedItemsGuiImpl
*/ */
@SuppressWarnings("DeprecatedIsStillUsed") final class PagedNestedGuiImpl extends AbstractPagedGui<Gui> {
public final class PagedNestedGuiImpl extends AbstractPagedGui<Gui> {
private List<Gui> guis; private List<Gui> guis;
@ -32,9 +25,7 @@ public final class PagedNestedGuiImpl extends AbstractPagedGui<Gui> {
* @param height The height of this Gui. * @param height The height of this Gui.
* @param guis The {@link Gui Guis} to use as pages. * @param guis The {@link Gui Guis} to use as pages.
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @deprecated Use {@link PagedGui#ofGuis(int, int, List, int...)} instead.
*/ */
@Deprecated
public PagedNestedGuiImpl(int width, int height, @Nullable List<@NotNull Gui> guis, int... contentListSlots) { public PagedNestedGuiImpl(int width, int height, @Nullable List<@NotNull Gui> guis, int... contentListSlots) {
super(width, height, false, contentListSlots); super(width, height, false, contentListSlots);
setContent(guis); setContent(guis);
@ -45,9 +36,7 @@ public final class PagedNestedGuiImpl extends AbstractPagedGui<Gui> {
* *
* @param guis The {@link Gui Guis} to use as pages. * @param guis The {@link Gui Guis} to use as pages.
* @param structure The {@link Structure} to use. * @param structure The {@link Structure} to use.
* @deprecated Use {@link PagedGui#ofGuis(Structure, List)} instead.
*/ */
@Deprecated
public PagedNestedGuiImpl(@Nullable List<@NotNull Gui> guis, @NotNull Structure structure) { public PagedNestedGuiImpl(@Nullable List<@NotNull Gui> guis, @NotNull Structure structure) {
super(structure.getWidth(), structure.getHeight(), false, structure); super(structure.getWidth(), structure.getHeight(), false, structure);
setContent(guis); setContent(guis);
@ -76,4 +65,18 @@ public final class PagedNestedGuiImpl extends AbstractPagedGui<Gui> {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public static final class Builder extends AbstractBuilder<Gui> {
@Override
public @NotNull PagedGui<Gui> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new PagedNestedGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
}
} }

@ -1,20 +1,40 @@
package xyz.xenondevs.invui.gui; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.impl.ScrollItemsGuiImpl;
import xyz.xenondevs.invui.gui.impl.ScrollNestedGuiImpl;
import xyz.xenondevs.invui.gui.impl.ScrollInventoryGuiImpl;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.Item; import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.virtualinventory.VirtualInventory; import xyz.xenondevs.invui.virtualinventory.VirtualInventory;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
@SuppressWarnings("deprecation")
public interface ScrollGui<C> extends Gui { public interface ScrollGui<C> extends Gui {
/**
* Creates a new {@link Builder Gui Builder} for a {@link ScrollGui} that uses {@link Item Items} as content.
*
* @return The new {@link Builder Gui Builder}.
*/
static @NotNull Builder<@NotNull Item> items() {
return new ScrollItemsGuiImpl.Builder();
}
/**
* Creates a new {@link ScrollGui} that uses {@link Item Items} as content after configuring a
* {@link Builder Gui Builder} using the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder Gui Builder}.
* @return The created {@link ScrollGui}.
*/
static @NotNull ScrollGui<@NotNull Item> items(@NotNull Consumer<@NotNull Builder<@NotNull Item>> consumer) {
Builder<@NotNull Item> builder = items();
consumer.accept(builder);
return builder.build();
}
/** /**
* Creates a new {@link ScrollGui}. * Creates a new {@link ScrollGui}.
* *
@ -24,7 +44,7 @@ public interface ScrollGui<C> extends Gui {
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @return The created {@link ScrollGui}. * @return The created {@link ScrollGui}.
*/ */
static @NotNull ScrollGui<Item> ofItems(int width, int height, @NotNull List<@NotNull Item> items, int... contentListSlots) { static @NotNull ScrollGui<@NotNull Item> ofItems(int width, int height, @NotNull List<@NotNull Item> items, int... contentListSlots) {
return new ScrollItemsGuiImpl(width, height, items, contentListSlots); return new ScrollItemsGuiImpl(width, height, items, contentListSlots);
} }
@ -35,10 +55,32 @@ public interface ScrollGui<C> extends Gui {
* @param items The {@link Item Items} to use. * @param items The {@link Item Items} to use.
* @return The created {@link ScrollGui}. * @return The created {@link ScrollGui}.
*/ */
static @NotNull ScrollGui<Item> ofItems(@NotNull Structure structure, @NotNull List<@NotNull Item> items) { static @NotNull ScrollGui<@NotNull Item> ofItems(@NotNull Structure structure, @NotNull List<@NotNull Item> items) {
return new ScrollItemsGuiImpl(items, structure); return new ScrollItemsGuiImpl(items, structure);
} }
/**
* Creates a new {@link Builder Gui Builder} for a {@link ScrollGui} that uses {@link Gui Guis} as content.
*
* @return The new {@link Builder Gui Builder}.
*/
static @NotNull Builder<@NotNull Gui> guis() {
return new ScrollNestedGuiImpl.Builder();
}
/**
* Creates a new {@link ScrollGui} that uses {@link Gui Guis} as content after configuring a
* {@link Builder Gui Builder} using the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder Gui Builder}.
* @return The created {@link ScrollGui}.
*/
static @NotNull ScrollGui<@NotNull Gui> guis(@NotNull Consumer<@NotNull Builder<@NotNull Gui>> consumer) {
Builder<@NotNull Gui> builder = guis();
consumer.accept(builder);
return builder.build();
}
/** /**
* Creates a new {@link ScrollGui}. * Creates a new {@link ScrollGui}.
* *
@ -48,7 +90,7 @@ public interface ScrollGui<C> extends Gui {
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @return The created {@link ScrollGui}. * @return The created {@link ScrollGui}.
*/ */
static @NotNull ScrollGui<Gui> ofGuis(int width, int height, @NotNull List<@NotNull Gui> guis, int... contentListSlots) { static @NotNull ScrollGui<@NotNull Gui> ofGuis(int width, int height, @NotNull List<@NotNull Gui> guis, int... contentListSlots) {
return new ScrollNestedGuiImpl(width, height, guis, contentListSlots); return new ScrollNestedGuiImpl(width, height, guis, contentListSlots);
} }
@ -59,10 +101,32 @@ public interface ScrollGui<C> extends Gui {
* @param guis The {@link Gui Guis} to use. * @param guis The {@link Gui Guis} to use.
* @return The created {@link ScrollGui}. * @return The created {@link ScrollGui}.
*/ */
static @NotNull ScrollGui<Gui> ofGuis(Structure structure, @NotNull List<@NotNull Gui> guis) { static @NotNull ScrollGui<@NotNull Gui> ofGuis(Structure structure, @NotNull List<@NotNull Gui> guis) {
return new ScrollNestedGuiImpl(guis, structure); return new ScrollNestedGuiImpl(guis, structure);
} }
/**
* Creates a new {@link Builder Gui Builder} for a {@link ScrollGui} that uses {@link VirtualInventory VirtualInventories} as content.
*
* @return The new {@link Builder Gui Builder}.
*/
static @NotNull Builder<@NotNull VirtualInventory> inventories() {
return new ScrollInventoryGuiImpl.Builder();
}
/**
* Creates a new {@link ScrollGui} that uses {@link VirtualInventory VirtualInventories} as content after configuring a
* {@link Builder Gui Builder} using the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder Gui Builder}.
* @return The created {@link ScrollGui}.
*/
static @NotNull ScrollGui<@NotNull VirtualInventory> inventories(@NotNull Consumer<@NotNull Builder<@NotNull VirtualInventory>> consumer) {
Builder<@NotNull VirtualInventory> builder = inventories();
consumer.accept(builder);
return builder.build();
}
/** /**
* Creates a new {@link ScrollGui}. * Creates a new {@link ScrollGui}.
* *
@ -72,7 +136,7 @@ public interface ScrollGui<C> extends Gui {
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @return The created {@link ScrollGui}. * @return The created {@link ScrollGui}.
*/ */
static @NotNull ScrollGui<VirtualInventory> ofInventories(int width, int height, @NotNull List<@NotNull VirtualInventory> inventories, int... contentListSlots) { static @NotNull ScrollGui<@NotNull VirtualInventory> ofInventories(int width, int height, @NotNull List<@NotNull VirtualInventory> inventories, int... contentListSlots) {
return new ScrollInventoryGuiImpl(width, height, inventories, contentListSlots); return new ScrollInventoryGuiImpl(width, height, inventories, contentListSlots);
} }
@ -83,7 +147,7 @@ public interface ScrollGui<C> extends Gui {
* @param inventories The {@link VirtualInventory VirtualInventories} to use. * @param inventories The {@link VirtualInventory VirtualInventories} to use.
* @return The created {@link ScrollGui}. * @return The created {@link ScrollGui}.
*/ */
static @NotNull ScrollGui<VirtualInventory> ofInventories(@NotNull Structure structure, @NotNull List<@NotNull VirtualInventory> inventories) { static @NotNull ScrollGui<@NotNull VirtualInventory> ofInventories(@NotNull Structure structure, @NotNull List<@NotNull VirtualInventory> inventories) {
return new ScrollInventoryGuiImpl(inventories, structure); return new ScrollInventoryGuiImpl(inventories, structure);
} }
@ -150,4 +214,49 @@ public interface ScrollGui<C> extends Gui {
*/ */
void removeScrollHandler(@NotNull BiConsumer<Integer, Integer> scrollHandler); void removeScrollHandler(@NotNull BiConsumer<Integer, Integer> scrollHandler);
/**
* A {@link ScrollGui} builder.
*
* @param <C> The content type.
*/
interface Builder<C> extends Gui.Builder<ScrollGui<C>, Builder<C>> {
/**
* Sets the content of the {@link ScrollGui} for all lines.
*
* @param content The content to set.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> setContent(@NotNull List<@NotNull C> content);
/**
* Adds content to the {@link ScrollGui}.
*
* @param content The content to add.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> addContent(@NotNull C content);
/**
* Adds content to the {@link ScrollGui}.
*
* @param handlers The content to add.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> setScrollHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers);
/**
* Adds a scroll handler to the {@link ScrollGui}.
*
* @param handler The scroll handler to add.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder<C> addScrollHandler(@NotNull BiConsumer<Integer, Integer> handler);
}
} }

@ -1,11 +1,7 @@
package xyz.xenondevs.invui.gui.impl; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.AbstractScrollGui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.gui.builder.GuiType;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.virtualinventory.VirtualInventory; import xyz.xenondevs.invui.virtualinventory.VirtualInventory;
@ -15,12 +11,10 @@ import java.util.List;
/** /**
* A {@link AbstractScrollGui} that uses {@link VirtualInventory VirtualInventories} as content. * A {@link AbstractScrollGui} that uses {@link VirtualInventory VirtualInventories} as content.
* *
* @see GuiType
* @see ScrollItemsGuiImpl * @see ScrollItemsGuiImpl
* @see ScrollNestedGuiImpl * @see ScrollNestedGuiImpl
*/ */
@SuppressWarnings("DeprecatedIsStillUsed") final class ScrollInventoryGuiImpl extends AbstractScrollGui<VirtualInventory> {
public final class ScrollInventoryGuiImpl extends AbstractScrollGui<VirtualInventory> {
private List<VirtualInventory> inventories; private List<VirtualInventory> inventories;
private List<SlotElement.VISlotElement> elements; private List<SlotElement.VISlotElement> elements;
@ -32,9 +26,7 @@ public final class ScrollInventoryGuiImpl extends AbstractScrollGui<VirtualInven
* @param height The width of this Gui. * @param height The width of this Gui.
* @param inventories The {@link VirtualInventory VirtualInventories} to use. * @param inventories The {@link VirtualInventory VirtualInventories} to use.
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @deprecated Use {@link ScrollGui#ofInventories(int, int, List, int...)} instead.
*/ */
@Deprecated
public ScrollInventoryGuiImpl(int width, int height, @Nullable List<@NotNull VirtualInventory> inventories, int... contentListSlots) { public ScrollInventoryGuiImpl(int width, int height, @Nullable List<@NotNull VirtualInventory> inventories, int... contentListSlots) {
super(width, height, false, contentListSlots); super(width, height, false, contentListSlots);
setContent(inventories); setContent(inventories);
@ -45,9 +37,7 @@ public final class ScrollInventoryGuiImpl extends AbstractScrollGui<VirtualInven
* *
* @param inventories The {@link VirtualInventory VirtualInventories} to use. * @param inventories The {@link VirtualInventory VirtualInventories} to use.
* @param structure The {@link Structure} to use. * @param structure The {@link Structure} to use.
* @deprecated Use {@link ScrollGui#ofInventories(Structure, List)} instead.
*/ */
@Deprecated
public ScrollInventoryGuiImpl(@Nullable List<@NotNull VirtualInventory> inventories, @NotNull Structure structure) { public ScrollInventoryGuiImpl(@Nullable List<@NotNull VirtualInventory> inventories, @NotNull Structure structure) {
super(structure.getWidth(), structure.getHeight(), false, structure); super(structure.getWidth(), structure.getHeight(), false, structure);
setContent(inventories); setContent(inventories);
@ -80,4 +70,18 @@ public final class ScrollInventoryGuiImpl extends AbstractScrollGui<VirtualInven
return (int) Math.ceil((double) elements.size() / (double) getLineLength()) - 1; return (int) Math.ceil((double) elements.size() / (double) getLineLength()) - 1;
} }
public static final class Builder extends AbstractBuilder<VirtualInventory> {
@Override
public @NotNull ScrollGui<VirtualInventory> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new ScrollInventoryGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
}
} }

@ -1,11 +1,7 @@
package xyz.xenondevs.invui.gui.impl; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.AbstractScrollGui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.gui.builder.GuiType;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.Item; import xyz.xenondevs.invui.item.Item;
@ -16,12 +12,10 @@ import java.util.stream.Collectors;
/** /**
* A {@link AbstractScrollGui} that uses {@link Item Items} as content. * A {@link AbstractScrollGui} that uses {@link Item Items} as content.
* *
* @see GuiType
* @see ScrollInventoryGuiImpl * @see ScrollInventoryGuiImpl
* @see ScrollNestedGuiImpl * @see ScrollNestedGuiImpl
*/ */
@SuppressWarnings("DeprecatedIsStillUsed") final class ScrollItemsGuiImpl extends AbstractScrollGui<Item> {
public final class ScrollItemsGuiImpl extends AbstractScrollGui<Item> {
private List<Item> items; private List<Item> items;
@ -32,9 +26,7 @@ public final class ScrollItemsGuiImpl extends AbstractScrollGui<Item> {
* @param height The height of this Gui. * @param height The height of this Gui.
* @param items The {@link Item Items} to use. * @param items The {@link Item Items} to use.
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @deprecated Use {@link ScrollGui#ofItems(int, int, List, int...)} instead.
*/ */
@Deprecated
public ScrollItemsGuiImpl(int width, int height, @Nullable List<@NotNull Item> items, int... contentListSlots) { public ScrollItemsGuiImpl(int width, int height, @Nullable List<@NotNull Item> items, int... contentListSlots) {
super(width, height, false, contentListSlots); super(width, height, false, contentListSlots);
setContent(items); setContent(items);
@ -45,9 +37,7 @@ public final class ScrollItemsGuiImpl extends AbstractScrollGui<Item> {
* *
* @param items The {@link Item Items} to use. * @param items The {@link Item Items} to use.
* @param structure The {@link Structure} to use. * @param structure The {@link Structure} to use.
* @deprecated Use {@link ScrollGui#ofItems(Structure, List)} instead.
*/ */
@Deprecated
public ScrollItemsGuiImpl(@Nullable List<@NotNull Item> items, @NotNull Structure structure) { public ScrollItemsGuiImpl(@Nullable List<@NotNull Item> items, @NotNull Structure structure) {
super(structure.getWidth(), structure.getHeight(), false, structure); super(structure.getWidth(), structure.getHeight(), false, structure);
setContent(items); setContent(items);
@ -71,4 +61,18 @@ public final class ScrollItemsGuiImpl extends AbstractScrollGui<Item> {
return (int) Math.ceil((double) items.size() / (double) getLineLength()) - 1; return (int) Math.ceil((double) items.size() / (double) getLineLength()) - 1;
} }
public static final class Builder extends AbstractBuilder<Item> {
@Override
public @NotNull ScrollGui<Item> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new ScrollItemsGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
}
} }

@ -1,12 +1,7 @@
package xyz.xenondevs.invui.gui.impl; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.AbstractScrollGui;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.gui.builder.GuiType;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import java.util.ArrayList; import java.util.ArrayList;
@ -15,12 +10,10 @@ import java.util.List;
/** /**
* A {@link AbstractScrollGui} that uses {@link Gui Guis} as content. * A {@link AbstractScrollGui} that uses {@link Gui Guis} as content.
* *
* @see GuiType
* @see ScrollItemsGuiImpl * @see ScrollItemsGuiImpl
* @see ScrollInventoryGuiImpl * @see ScrollInventoryGuiImpl
*/ */
@SuppressWarnings("DeprecatedIsStillUsed") final class ScrollNestedGuiImpl extends AbstractScrollGui<Gui> {
public final class ScrollNestedGuiImpl extends AbstractScrollGui<Gui> {
private List<Gui> guis; private List<Gui> guis;
private List<SlotElement.LinkedSlotElement> elements; private List<SlotElement.LinkedSlotElement> elements;
@ -32,9 +25,7 @@ public final class ScrollNestedGuiImpl extends AbstractScrollGui<Gui> {
* @param height The height of this Gui. * @param height The height of this Gui.
* @param guis The {@link Gui Guis} to use. * @param guis The {@link Gui Guis} to use.
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @deprecated Use {@link ScrollGui#ofGuis(int, int, List, int...)} instead.
*/ */
@Deprecated
public ScrollNestedGuiImpl(int width, int height, @Nullable List<@NotNull Gui> guis, int... contentListSlots) { public ScrollNestedGuiImpl(int width, int height, @Nullable List<@NotNull Gui> guis, int... contentListSlots) {
super(width, height, false, contentListSlots); super(width, height, false, contentListSlots);
setContent(guis); setContent(guis);
@ -45,9 +36,7 @@ public final class ScrollNestedGuiImpl extends AbstractScrollGui<Gui> {
* *
* @param guis The {@link Gui Guis} to use. * @param guis The {@link Gui Guis} to use.
* @param structure The {@link Structure} to use. * @param structure The {@link Structure} to use.
* @deprecated Use {@link ScrollGui#ofGuis(Structure, List)} instead.
*/ */
@Deprecated
public ScrollNestedGuiImpl(@Nullable List<@NotNull Gui> guis, @NotNull Structure structure) { public ScrollNestedGuiImpl(@Nullable List<@NotNull Gui> guis, @NotNull Structure structure) {
super(structure.getWidth(), structure.getHeight(), false, structure); super(structure.getWidth(), structure.getHeight(), false, structure);
setContent(guis); setContent(guis);
@ -80,4 +69,19 @@ public final class ScrollNestedGuiImpl extends AbstractScrollGui<Gui> {
return (int) Math.ceil((double) elements.size() / (double) getLineLength()) - 1; return (int) Math.ceil((double) elements.size() / (double) getLineLength()) - 1;
} }
public static final class Builder extends AbstractBuilder<Gui> {
@Override
public @NotNull ScrollGui<Gui> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new ScrollNestedGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
}
} }

@ -1,16 +1,37 @@
package xyz.xenondevs.invui.gui; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.impl.TabGuiImpl;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
@SuppressWarnings("deprecation")
public interface TabGui extends Gui { public interface TabGui extends Gui {
/**
* Creates a new {@link Builder Gui Builder} for a {@link TabGui}.
*
* @return The new {@link Builder Gui Builder}.
*/
static @NotNull Builder normal() {
return new TabGuiImpl.BuilderImpl();
}
/**
* Creates a new {@link TabGui} after configuring a {@link Builder Gui Builder} using the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder Gui Builder}.
* @return The created {@link TabGui}.
*/
static @NotNull TabGui normal(@NotNull Consumer<@NotNull Builder> consumer) {
Builder builder = normal();
consumer.accept(builder);
return builder.build();
}
/** /**
* Creates a new {@link TabGui}. * Creates a new {@link TabGui}.
* *
@ -92,4 +113,49 @@ public interface TabGui extends Gui {
*/ */
void removeTabChangeHandler(@NotNull BiConsumer<Integer, Integer> handler); void removeTabChangeHandler(@NotNull BiConsumer<Integer, Integer> handler);
/**
* A {@link TabGui} builder.
*/
interface Builder extends Gui.Builder<TabGui, Builder> {
/**
* Sets the tabs of the {@link TabGui}.
* Individual tabs can be null to disable them, but there must at least one tab.
*
* @param tabs The tabs of the {@link TabGui}.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder setTabs(@NotNull List<@Nullable Gui> tabs);
/**
* Adds a tab to the {@link TabGui}.
* Individual tabs can be null to disable them, but there must at least one tab.
*
* @param tab The tab to add.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder addTab(@Nullable Gui tab);
/**
* Sets the tab change handlers of the {@link TabGui}.
*
* @param handlers The tab change handlers of the {@link TabGui}.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder setTabChangeHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers);
/**
* Adds a tab change handler to the {@link TabGui}.
*
* @param handler The tab change handler to add.
* @return This {@link Builder Gui Builder}.
*/
@Contract("_ -> this")
Builder addTabChangeHandler(@NotNull BiConsumer<Integer, Integer> handler);
}
} }

@ -1,12 +1,7 @@
package xyz.xenondevs.invui.gui.impl; package xyz.xenondevs.invui.gui;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.AbstractTabGui;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.gui.TabGui;
import xyz.xenondevs.invui.gui.builder.GuiType;
import xyz.xenondevs.invui.gui.structure.Structure; import xyz.xenondevs.invui.gui.structure.Structure;
import java.util.ArrayList; import java.util.ArrayList;
@ -16,11 +11,8 @@ import java.util.stream.Collectors;
/** /**
* 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 GuiType
*/ */
@SuppressWarnings("DeprecatedIsStillUsed") final class TabGuiImpl extends AbstractTabGui {
public final class TabGuiImpl extends AbstractTabGui {
private final List<Gui> tabs; private final List<Gui> tabs;
private final List<List<SlotElement>> linkingElements; private final List<List<SlotElement>> linkingElements;
@ -32,9 +24,7 @@ public final class TabGuiImpl extends AbstractTabGui {
* @param height The height of this Gui. * @param height The height of this Gui.
* @param tabs The {@link Gui Guis} to use as tabs. * @param tabs The {@link Gui Guis} to use as tabs.
* @param contentListSlots The slots where content should be displayed. * @param contentListSlots The slots where content should be displayed.
* @deprecated Use {@link TabGui#of(int, int, List, int...)} instead.
*/ */
@Deprecated
public TabGuiImpl(int width, int height, @NotNull List<@Nullable Gui> tabs, int[] contentListSlots) { public TabGuiImpl(int width, int height, @NotNull List<@Nullable Gui> tabs, int[] contentListSlots) {
super(width, height, tabs.size(), contentListSlots); super(width, height, tabs.size(), contentListSlots);
this.linkingElements = tabs.stream().map(this::getLinkingElements).collect(Collectors.toList()); this.linkingElements = tabs.stream().map(this::getLinkingElements).collect(Collectors.toList());
@ -48,9 +38,7 @@ public final class TabGuiImpl extends AbstractTabGui {
* *
* @param tabs The {@link Gui Guis} to use as tabs. * @param tabs The {@link Gui Guis} to use as tabs.
* @param structure The {@link Structure} to use. * @param structure The {@link Structure} to use.
* @deprecated Use {@link TabGui#of(Structure, List)} instead.
*/ */
@Deprecated
public TabGuiImpl(@NotNull List<@Nullable Gui> tabs, @NotNull Structure structure) { public TabGuiImpl(@NotNull List<@Nullable Gui> tabs, @NotNull Structure structure) {
super(structure.getWidth(), structure.getHeight(), tabs.size(), structure); super(structure.getWidth(), structure.getHeight(), tabs.size(), structure);
this.linkingElements = tabs.stream().map(this::getLinkingElements).collect(Collectors.toList()); this.linkingElements = tabs.stream().map(this::getLinkingElements).collect(Collectors.toList());
@ -85,4 +73,19 @@ public final class TabGuiImpl extends AbstractTabGui {
return linkingElements.get(tab); return linkingElements.get(tab);
} }
public static final class BuilderImpl extends AbstractBuilder implements TabGui.Builder {
@Override
public @NotNull TabGui build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
if (tabs == null)
throw new IllegalStateException("Tabs are not defined.");
var gui = new TabGuiImpl(tabs, structure);
applyModifiers(gui);
return gui;
}
}
} }

@ -1,159 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ShapedRecipe;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.gui.structure.Marker;
import xyz.xenondevs.invui.gui.structure.Structure;
import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.item.ItemProvider;
import xyz.xenondevs.invui.item.ItemWrapper;
import xyz.xenondevs.invui.virtualinventory.VirtualInventory;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* A builder class to easily construct {@link Gui Guis}.<br>
* It provides similar functionality to Bukkit's {@link ShapedRecipe}, as it
* allows for a structure String which defines the layout of the {@link Gui}.
*/
public abstract class AbstractGuiBuilder<G extends Gui, S extends AbstractGuiBuilder<G, S>> implements GuiBuilder<G> {
protected Structure structure;
protected ItemProvider background;
protected List<Consumer<Gui>> modifiers;
@Contract("_, _, _, -> this")
public S setStructure(int width, int height, @NotNull String structureData) {
structure = new Structure(width, height, structureData);
return getThis();
}
@Contract("_ -> this")
public S setStructure(@NotNull String... structureData) {
structure = new Structure(structureData);
return getThis();
}
@Contract("_ -> this")
public S setStructure(@NotNull Structure structure) {
this.structure = structure;
return getThis();
}
@Contract("_, _ -> this")
public S addIngredient(char key, @NotNull ItemStack itemStack) {
structure.addIngredient(key, itemStack);
return getThis();
}
@Contract("_, _ -> this")
public S addIngredient(char key, @NotNull ItemProvider itemProvider) {
structure.addIngredient(key, itemProvider);
return getThis();
}
@Contract("_, _ -> this")
public S addIngredient(char key, @NotNull Item item) {
structure.addIngredient(key, item);
return getThis();
}
@Contract("_, _ -> this")
public S addIngredient(char key, @NotNull VirtualInventory inventory) {
structure.addIngredient(key, inventory);
return getThis();
}
@Contract("_, _, _ -> this")
public S addIngredient(char key, @NotNull VirtualInventory inventory, @Nullable ItemProvider background) {
structure.addIngredient(key, inventory, background);
return getThis();
}
@Contract("_, _ -> this")
public S addIngredient(char key, @NotNull SlotElement element) {
structure.addIngredient(key, element);
return getThis();
}
@Contract("_, _ -> this")
public S addIngredient(char key, @NotNull Marker marker) {
structure.addIngredient(key, marker);
return getThis();
}
@Contract("_, _ -> this")
public S addIngredient(char key, @NotNull Supplier<? extends Item> itemSupplier) {
structure.addIngredient(key, itemSupplier);
return getThis();
}
@Contract("_, _ -> this")
public S addIngredientElementSupplier(char key, @NotNull Supplier<? extends SlotElement> elementSupplier) {
structure.addIngredientElementSupplier(key, elementSupplier);
return getThis();
}
@Contract("_ -> this")
public S setBackground(@NotNull ItemProvider itemProvider) {
background = itemProvider;
return getThis();
}
@Contract("_ -> this")
public S setBackground(@NotNull ItemStack itemStack) {
background = new ItemWrapper(itemStack);
return getThis();
}
@Contract("_ -> this")
public S addModifier(@NotNull Consumer<@NotNull Gui> modifier) {
if (modifiers == null)
modifiers = new ArrayList<>();
modifiers.add(modifier);
return getThis();
}
@Contract("_ -> this")
public S setModifiers(@NotNull List<@NotNull Consumer<@NotNull Gui>> modifiers) {
this.modifiers = modifiers;
return getThis();
}
protected void applyModifiers(@NotNull G gui) {
if (background != null) {
gui.setBackground(background);
}
if (modifiers != null) {
modifiers.forEach(modifier -> modifier.accept(gui));
}
}
@SuppressWarnings("unchecked")
@Override
public @NotNull AbstractGuiBuilder<G, S> clone() {
try {
var clone = (AbstractGuiBuilder<G, S>) super.clone();
clone.structure = structure.clone();
if (modifiers != null)
clone.modifiers = new ArrayList<>(modifiers);
return clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
@Contract(value = "-> this", pure = true)
protected abstract S getThis();
}

@ -1,60 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.PagedGui;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
public abstract class AbstractPagedGuiBuilder<C, S extends AbstractPagedGuiBuilder<C, S>> extends AbstractGuiBuilder<PagedGui<C>, S> {
protected List<C> content;
protected List<BiConsumer<Integer, Integer>> pageChangeHandlers;
@Contract("_ -> this")
public S setContent(@NotNull List<@NotNull C> content) {
this.content = content;
return getThis();
}
@Contract("_ -> this")
public S addContent(@NotNull C content) {
if (this.content == null)
this.content = new ArrayList<>();
this.content.add(content);
return getThis();
}
@Contract("_ -> this")
public S setPageChangeHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers) {
pageChangeHandlers = handlers;
return getThis();
}
@Contract("_ -> this")
public S addPageChangeHandler(@NotNull BiConsumer<Integer, Integer> handler) {
if (pageChangeHandlers == null)
pageChangeHandlers = new ArrayList<>(1);
pageChangeHandlers.add(handler);
return getThis();
}
@Override
protected void applyModifiers(@NotNull PagedGui<C> gui) {
super.applyModifiers(gui);
gui.setPageChangeHandlers(pageChangeHandlers);
}
@Override
public @NotNull AbstractPagedGuiBuilder<C, S> clone() {
var clone = (AbstractPagedGuiBuilder<C, S>) super.clone();
clone.content = new ArrayList<>(content);
clone.pageChangeHandlers = new ArrayList<>(pageChangeHandlers);
return clone;
}
}

@ -1,60 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.ScrollGui;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
public abstract class AbstractScrollGuiBuilder<C, S extends AbstractScrollGuiBuilder<C, S>> extends AbstractGuiBuilder<ScrollGui<C>, S>{
protected List<C> content;
protected List<BiConsumer<Integer, Integer>> scrollHandlers;
@Contract("_ -> this")
public S setContent(@NotNull List<@NotNull C> content) {
this.content = content;
return getThis();
}
@Contract("_ -> this")
public S addContent(@NotNull C content) {
if (this.content == null)
this.content = new ArrayList<>();
this.content.add(content);
return getThis();
}
@Contract("_ -> this")
public S setScrollHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers) {
scrollHandlers = handlers;
return getThis();
}
@Contract("_ -> this")
public S addScrollHandler(@NotNull BiConsumer<Integer, Integer> handler) {
if (scrollHandlers == null)
scrollHandlers = new ArrayList<>(1);
scrollHandlers.add(handler);
return getThis();
}
@Override
protected void applyModifiers(@NotNull ScrollGui<C> gui) {
super.applyModifiers(gui);
gui.setScrollHandlers(scrollHandlers);
}
@Override
public @NotNull AbstractScrollGuiBuilder<C, S> clone() {
var clone = (AbstractScrollGuiBuilder<C, S>) super.clone();
clone.content = new ArrayList<>(content);
clone.scrollHandlers = new ArrayList<>(scrollHandlers);
return clone;
}
}

@ -1,15 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
public interface GuiBuilder<G extends Gui> extends Cloneable {
@Contract("-> new")
@NotNull G build();
@Contract("-> new")
@NotNull GuiBuilder<G> clone();
}

@ -1,42 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.TabGui;
import xyz.xenondevs.invui.item.Item;
import xyz.xenondevs.invui.virtualinventory.VirtualInventory;
import java.util.function.Consumer;
public interface GuiType<G extends Gui, B extends GuiBuilder<G>> {
GuiType<Gui, NormalGuiBuilder> NORMAL = NormalGuiBuilder::new;
GuiType<PagedGui<Item>, PagedItemsGuiBuilder> PAGED_ITEMS = PagedItemsGuiBuilder::new;
GuiType<PagedGui<Gui>, PagedNestedGuiBuilder> PAGED_GUIS = PagedNestedGuiBuilder::new;
GuiType<TabGui, TabGuiBuilder> TAB = TabGuiBuilder::new;
GuiType<ScrollGui<Item>, ScrollItemsGuiBuilder> SCROLL_ITEMS = ScrollItemsGuiBuilder::new;
GuiType<ScrollGui<Gui>, ScrollNestedGuiBuilder> SCROLL_GUIS = ScrollNestedGuiBuilder::new;
GuiType<ScrollGui<VirtualInventory>, ScrollInventoryGuiBuilder> SCROLL_INVENTORY = ScrollInventoryGuiBuilder::new;
/**
* Creates a new {@link GuiBuilder} for this {@link GuiType}.
*
* @return The created {@link GuiBuilder}.
*/
@NotNull B builder();
/**
* Creates a new {@link Gui} after modifying the {@link GuiBuilder} with the given {@link Consumer}.
*
* @param builderConsumer The {@link Consumer} which modifies the {@link GuiBuilder}.
* @return The new {@link Gui}.
*/
default @NotNull G createGui(@NotNull Consumer<B> builderConsumer) {
var builder = builder();
builderConsumer.accept(builder);
return builder.build();
}
}

@ -1,33 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.impl.NormalGuiImpl;
public final class NormalGuiBuilder extends AbstractGuiBuilder<Gui, NormalGuiBuilder> {
NormalGuiBuilder() {
}
@SuppressWarnings("deprecation")
@Override
public @NotNull Gui build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new NormalGuiImpl(structure);
applyModifiers(gui);
return gui;
}
@Override
protected NormalGuiBuilder getThis() {
return this;
}
@Override
public @NotNull NormalGuiBuilder clone() {
return (NormalGuiBuilder) super.clone();
}
}

@ -1,34 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.gui.impl.PagedItemsGuiImpl;
import xyz.xenondevs.invui.item.Item;
public final class PagedItemsGuiBuilder extends AbstractPagedGuiBuilder<Item, PagedItemsGuiBuilder> {
PagedItemsGuiBuilder() {
}
@SuppressWarnings("deprecation")
@Override
public @NotNull PagedGui<Item> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new PagedItemsGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
@Override
protected PagedItemsGuiBuilder getThis() {
return this;
}
@Override
public @NotNull PagedItemsGuiBuilder clone() {
return (PagedItemsGuiBuilder) super.clone();
}
}

@ -1,34 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.PagedGui;
import xyz.xenondevs.invui.gui.impl.PagedNestedGuiImpl;
public final class PagedNestedGuiBuilder extends AbstractPagedGuiBuilder<Gui, PagedNestedGuiBuilder> {
PagedNestedGuiBuilder() {
}
@SuppressWarnings("deprecation")
@Override
public @NotNull PagedGui<Gui> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new PagedNestedGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
@Override
protected PagedNestedGuiBuilder getThis() {
return this;
}
@Override
public @NotNull PagedNestedGuiBuilder clone() {
return (PagedNestedGuiBuilder) super.clone();
}
}

@ -1,34 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.impl.ScrollInventoryGuiImpl;
import xyz.xenondevs.invui.virtualinventory.VirtualInventory;
public final class ScrollInventoryGuiBuilder extends AbstractScrollGuiBuilder<VirtualInventory, ScrollInventoryGuiBuilder> {
ScrollInventoryGuiBuilder() {
}
@SuppressWarnings("deprecation")
@Override
public @NotNull ScrollGui<VirtualInventory> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new ScrollInventoryGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
@Override
protected ScrollInventoryGuiBuilder getThis() {
return this;
}
@Override
public @NotNull ScrollInventoryGuiBuilder clone() {
return (ScrollInventoryGuiBuilder) super.clone();
}
}

@ -1,34 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.impl.ScrollItemsGuiImpl;
import xyz.xenondevs.invui.item.Item;
public final class ScrollItemsGuiBuilder extends AbstractScrollGuiBuilder<Item, ScrollItemsGuiBuilder> {
ScrollItemsGuiBuilder() {
}
@SuppressWarnings("deprecation")
@Override
public @NotNull ScrollGui<Item> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new ScrollItemsGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
@Override
protected ScrollItemsGuiBuilder getThis() {
return this;
}
@Override
public @NotNull ScrollItemsGuiBuilder clone() {
return (ScrollItemsGuiBuilder) super.clone();
}
}

@ -1,34 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.ScrollGui;
import xyz.xenondevs.invui.gui.impl.ScrollNestedGuiImpl;
public final class ScrollNestedGuiBuilder extends AbstractScrollGuiBuilder<Gui, ScrollNestedGuiBuilder>{
ScrollNestedGuiBuilder() {
}
@SuppressWarnings("deprecation")
@Override
public @NotNull ScrollGui<Gui> build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
var gui = new ScrollNestedGuiImpl(content, structure);
applyModifiers(gui);
return gui;
}
@Override
protected ScrollNestedGuiBuilder getThis() {
return this;
}
@Override
public @NotNull ScrollNestedGuiBuilder clone() {
return (ScrollNestedGuiBuilder) super.clone();
}
}

@ -1,83 +0,0 @@
package xyz.xenondevs.invui.gui.builder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.TabGui;
import xyz.xenondevs.invui.gui.impl.TabGuiImpl;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
public final class TabGuiBuilder extends AbstractGuiBuilder<TabGui, TabGuiBuilder> {
private List<Gui> tabs;
private List<BiConsumer<Integer, Integer>> tabChangeHandlers;
TabGuiBuilder() {
}
@Contract("_ -> this")
public TabGuiBuilder setTabs(@NotNull List<@Nullable Gui> tabs) {
this.tabs = tabs;
return this;
}
@Contract("_ -> this")
public TabGuiBuilder addTab(@Nullable Gui tab) {
if (this.tabs == null)
this.tabs = new ArrayList<>();
this.tabs.add(tab);
return this;
}
@Contract("_ -> this")
public TabGuiBuilder addTabChangeHandler(@NotNull BiConsumer<Integer, Integer> handler) {
if (tabChangeHandlers == null)
tabChangeHandlers = new ArrayList<>(1);
tabChangeHandlers.add(handler);
return this;
}
@Contract("_ -> this")
public TabGuiBuilder setTabChangeHandlers(@NotNull List<@NotNull BiConsumer<Integer, Integer>> handlers) {
tabChangeHandlers = handlers;
return this;
}
@Override
protected void applyModifiers(@NotNull TabGui gui) {
super.applyModifiers(gui);
gui.setTabChangeHandlers(tabChangeHandlers);
}
@SuppressWarnings("deprecation")
@Override
public @NotNull TabGui build() {
if (structure == null)
throw new IllegalStateException("Structure is not defined.");
if (tabs == null)
throw new IllegalStateException("Tabs are not defined.");
var gui = new TabGuiImpl(tabs, structure);
applyModifiers(gui);
return gui;
}
@Override
protected TabGuiBuilder getThis() {
return this;
}
@Override
public @NotNull TabGuiBuilder clone() {
var clone = (TabGuiBuilder) super.clone();
clone.tabs = new ArrayList<>(tabs);
clone.tabChangeHandlers = new ArrayList<>(tabChangeHandlers);
return clone;
}
}

@ -5,6 +5,7 @@ import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper; import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui; import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.gui.Gui;
@ -13,6 +14,7 @@ import xyz.xenondevs.invui.util.InventoryUtils;
import xyz.xenondevs.invui.util.Pair; import xyz.xenondevs.invui.util.Pair;
import java.util.UUID; import java.util.UUID;
import java.util.function.Supplier;
/** /**
* A {@link Window} that just uses the top {@link Inventory}. * A {@link Window} that just uses the top {@link Inventory}.
@ -106,4 +108,32 @@ public abstract class AbstractSingleWindow extends AbstractWindow {
return gui; return gui;
} }
@SuppressWarnings("unchecked")
public abstract static class AbstractBuilder<W extends Window, V, S extends Builder.Single<W, V, S>>
extends AbstractWindow.AbstractBuilder<W, V, S>
implements Builder.Single<W, V, S>
{
protected Supplier<Gui> guiSupplier;
@Override
public S setGui(@NotNull Supplier<Gui> guiSupplier) {
this.guiSupplier = guiSupplier;
return (S) this;
}
@Override
public S setGui(@NotNull Gui gui) {
this.guiSupplier = () -> gui;
return (S) this;
}
@Override
public S setGui(@NotNull Gui.Builder<?, ?> builder) {
this.guiSupplier = builder::build;
return (S) this;
}
}
} }

@ -3,6 +3,7 @@ package xyz.xenondevs.invui.window;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper; import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui; import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.gui.Gui;
@ -10,6 +11,8 @@ import xyz.xenondevs.invui.gui.SlotElement;
import xyz.xenondevs.invui.util.Pair; import xyz.xenondevs.invui.util.Pair;
import xyz.xenondevs.invui.util.SlotUtils; import xyz.xenondevs.invui.util.SlotUtils;
import java.util.function.Supplier;
/** /**
* A {@link Window} where top and player {@link Inventory} are affected by different {@link Gui}s. * A {@link Window} where top and player {@link Inventory} are affected by different {@link Gui}s.
*/ */
@ -64,4 +67,51 @@ public abstract class AbstractSplitWindow extends AbstractDoubleWindow {
return new AbstractGui[] {upperGui, lowerGui}; return new AbstractGui[] {upperGui, lowerGui};
} }
@SuppressWarnings("unchecked")
public static abstract class AbstractBuilder<W extends Window, V, S extends Window.Builder.Double<W, V, S>>
extends AbstractWindow.AbstractBuilder<W, V, S>
implements Window.Builder.Double<W, V, S>
{
protected Supplier<Gui> upperGuiSupplier;
protected Supplier<Gui> lowerGuiSupplier;
@Override
public S setUpperGui(@NotNull Supplier<Gui> guiSupplier) {
this.upperGuiSupplier = guiSupplier;
return (S) this;
}
@Override
public S setUpperGui(@NotNull Gui gui) {
this.upperGuiSupplier = () -> gui;
return (S) this;
}
@Override
public S setUpperGui(@NotNull Gui.Builder<?, ?> builder) {
this.upperGuiSupplier = builder::build;
return (S) this;
}
@Override
public S setLowerGui(@NotNull Supplier<Gui> guiSupplier) {
this.lowerGuiSupplier = guiSupplier;
return (S) this;
}
@Override
public S setLowerGui(@NotNull Gui gui) {
this.lowerGuiSupplier = () -> gui;
return (S) this;
}
@Override
public S setLowerGui(@NotNull Gui.Builder<?, ?> builder) {
this.lowerGuiSupplier = builder::build;
return (S) this;
}
}
} }

@ -34,6 +34,7 @@ import xyz.xenondevs.invui.virtualinventory.event.PlayerUpdateReason;
import xyz.xenondevs.invui.virtualinventory.event.UpdateReason; import xyz.xenondevs.invui.virtualinventory.event.UpdateReason;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
public abstract class AbstractWindow implements Window, GuiParent { public abstract class AbstractWindow implements Window, GuiParent {
@ -365,4 +366,108 @@ public abstract class AbstractWindow implements Window, GuiParent {
public abstract void handleViewerDeath(PlayerDeathEvent event); public abstract void handleViewerDeath(PlayerDeathEvent event);
@SuppressWarnings("unchecked")
public static abstract class AbstractBuilder<W extends Window, V, S extends Window.Builder<W, V, S>> implements Window.Builder<W, V, S> {
protected V viewer;
protected ComponentWrapper title;
protected boolean closeable = true;
protected boolean retain = false;
protected List<Runnable> closeHandlers;
protected List<Consumer<Window>> modifiers;
@Override
public S setViewer(@NotNull V viewer) {
this.viewer = viewer;
return (S) this;
}
@Override
public S setTitle(@NotNull ComponentWrapper title) {
this.title = title;
return (S) this;
}
@Override
public S setTitle(@NotNull BaseComponent @NotNull [] title) {
this.title = new BaseComponentWrapper(title);
return (S) this;
}
@Override
public S setTitle(@NotNull String title) {
this.title = new BaseComponentWrapper(TextComponent.fromLegacyText(title));
return (S) this;
}
@Override
public S setCloseable(boolean closeable) {
this.closeable = closeable;
return (S) this;
}
@Override
public S setRetain(boolean retain) {
this.retain = retain;
return (S) this;
}
@Override
public S setCloseHandlers(List<Runnable> closeHandlers) {
this.closeHandlers = closeHandlers;
return (S) this;
}
@Override
public S addCloseHandler(Runnable closeHandler) {
if (closeHandlers == null)
closeHandlers = new ArrayList<>();
closeHandlers.add(closeHandler);
return (S) this;
}
@Override
public S setModifiers(List<Consumer<Window>> modifiers) {
this.modifiers = modifiers;
return (S) this;
}
@Override
public S addModifier(Consumer<Window> modifier) {
if (modifiers == null)
modifiers = new ArrayList<>();
modifiers.add(modifier);
return (S) this;
}
protected void applyModifiers(W window) {
if (closeHandlers != null)
window.setCloseHandlers(closeHandlers);
if (modifiers != null)
modifiers.forEach(modifier -> modifier.accept(window));
}
@SuppressWarnings("unchecked")
@Override
public @NotNull S clone() {
try {
var clone = (AbstractBuilder<W, V, S>) super.clone();
if (title != null)
clone.title = title.clone();
if (closeHandlers != null)
clone.closeHandlers = new ArrayList<>(closeHandlers);
if (modifiers != null)
clone.modifiers = new ArrayList<>(modifiers);
return (S) clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
} }

@ -1,4 +1,4 @@
package xyz.xenondevs.invui.window.impl; package xyz.xenondevs.invui.window;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
@ -8,13 +8,12 @@ import xyz.xenondevs.inventoryaccess.InventoryAccess;
import xyz.xenondevs.inventoryaccess.abstraction.inventory.AnvilInventory; import xyz.xenondevs.inventoryaccess.abstraction.inventory.AnvilInventory;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper; import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui; import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.AbstractSingleWindow;
import xyz.xenondevs.invui.window.AnvilWindow;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
public final class AnvilSingleWindowImpl extends AbstractSingleWindow implements AnvilWindow { final class AnvilSingleWindowImpl extends AbstractSingleWindow implements AnvilWindow {
private final AnvilInventory anvilInventory; private final AnvilInventory anvilInventory;
@ -53,4 +52,49 @@ public final class AnvilSingleWindowImpl extends AbstractSingleWindow implements
return anvilInventory.getRenameText(); return anvilInventory.getRenameText();
} }
public static final class BuilderImpl
extends AbstractSingleWindow.AbstractBuilder<AnvilWindow, Player, AnvilWindow.Builder.Single>
implements AnvilWindow.Builder.Single
{
private List<Consumer<String>> renameHandlers;
@Override
public BuilderImpl setRenameHandlers(@NotNull List<@NotNull Consumer<String>> renameHandlers) {
this.renameHandlers = renameHandlers;
return this;
}
@Override
public BuilderImpl addRenameHandler(@NotNull Consumer<String> renameHandler) {
if (renameHandlers == null)
renameHandlers = new ArrayList<>();
renameHandlers.add(renameHandler);
return this;
}
@Override
public @NotNull AnvilWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new AnvilSingleWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
renameHandlers,
closeable,
retain
);
applyModifiers(window);
return window;
}
}
} }

@ -0,0 +1,105 @@
package xyz.xenondevs.invui.window;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.InventoryAccess;
import xyz.xenondevs.inventoryaccess.abstraction.inventory.AnvilInventory;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
final class AnvilSplitWindowImpl extends AbstractSplitWindow implements AnvilWindow {
private final AnvilInventory anvilInventory;
public AnvilSplitWindowImpl(
@NotNull Player player,
@Nullable ComponentWrapper title,
@NotNull AbstractGui upperGui,
@NotNull AbstractGui lowerGui,
@Nullable List<@NotNull Consumer<@NotNull String>> renameHandlers,
boolean closeable,
boolean retain
) {
super(player, title, upperGui, lowerGui, null, false, closeable, retain);
anvilInventory = InventoryAccess.createAnvilInventory(player, title, renameHandlers);
upperInventory = anvilInventory.getBukkitInventory();
initUpperItems();
register();
}
@Override
protected void setUpperInvItem(int slot, ItemStack itemStack) {
anvilInventory.setItem(slot, itemStack);
}
@Override
public void show() {
if (isRemoved()) throw new IllegalStateException("The Window has already been closed.");
Player viewer = getViewer();
if (viewer == null) throw new IllegalStateException("The player is not online.");
anvilInventory.open();
}
@Override
public String getRenameText() {
return anvilInventory.getRenameText();
}
public static final class BuilderImpl
extends AbstractSplitWindow.AbstractBuilder<AnvilWindow, Player, AnvilWindow.Builder.Split>
implements AnvilWindow.Builder.Split
{
private List<Consumer<String>> renameHandlers;
@Override
public BuilderImpl setRenameHandlers(@NotNull List<@NotNull Consumer<String>> renameHandlers) {
this.renameHandlers = renameHandlers;
return this;
}
@Override
public BuilderImpl addRenameHandler(@NotNull Consumer<String> renameHandler) {
if (renameHandlers == null)
renameHandlers = new ArrayList<>();
renameHandlers.add(renameHandler);
return this;
}
@Override
public @NotNull AnvilWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (upperGuiSupplier == null)
throw new IllegalStateException("Upper Gui is not defined.");
if (lowerGuiSupplier == null)
throw new IllegalStateException("Lower Gui is not defined.");
var window = new AnvilSplitWindowImpl(
viewer,
title,
(AbstractGui) upperGuiSupplier.get(),
(AbstractGui) lowerGuiSupplier.get(),
renameHandlers,
closeable,
retain
);
applyModifiers(window);
return window;
}
}
}

@ -1,7 +1,49 @@
package xyz.xenondevs.invui.window; package xyz.xenondevs.invui.window;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.function.Consumer;
public interface AnvilWindow extends Window { public interface AnvilWindow extends Window {
String getRenameText(); static @NotNull Builder.Single single() {
return new AnvilSingleWindowImpl.BuilderImpl();
}
static @NotNull AnvilWindow single(@NotNull Consumer<Builder.@NotNull Single> consumer) {
Builder.Single builder = single();
consumer.accept(builder);
return builder.build();
}
static @NotNull Builder.Split split() {
return new AnvilSplitWindowImpl.BuilderImpl();
}
static @NotNull AnvilWindow split(Consumer<Builder.@NotNull Split> consumer) {
Builder.Split builder = split();
consumer.accept(builder);
return builder.build();
}
@Nullable String getRenameText();
interface Builder<S extends Builder<S>> extends Window.Builder<AnvilWindow, Player, S> {
@Contract("_ -> this")
S setRenameHandlers(@NotNull List<@NotNull Consumer<String>> renameHandlers);
@Contract("_ -> this")
S addRenameHandler(@NotNull Consumer<String> renameHandler);
interface Single extends Builder<Single>, Window.Builder.Single<AnvilWindow, Player, Single> {}
interface Split extends Builder<Split>, Window.Builder.Double<AnvilWindow, Player, Split> {}
}
} }

@ -1,4 +1,4 @@
package xyz.xenondevs.invui.window.impl; package xyz.xenondevs.invui.window;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -14,12 +14,10 @@ import xyz.xenondevs.inventoryaccess.map.MapIcon;
import xyz.xenondevs.inventoryaccess.map.MapPatch; import xyz.xenondevs.inventoryaccess.map.MapPatch;
import xyz.xenondevs.invui.gui.AbstractGui; import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.util.MathUtils; import xyz.xenondevs.invui.util.MathUtils;
import xyz.xenondevs.invui.window.AbstractSingleWindow;
import xyz.xenondevs.invui.window.CartographyWindow;
import java.util.List; import java.util.List;
public final class CartographySingleWindowImpl extends AbstractSingleWindow implements CartographyWindow { final class CartographySingleWindowImpl extends AbstractSingleWindow implements CartographyWindow {
private final CartographyInventory cartographyInventory; private final CartographyInventory cartographyInventory;
private int mapId; private int mapId;
@ -83,4 +81,31 @@ public final class CartographySingleWindowImpl extends AbstractSingleWindow impl
cartographyInventory.open(); cartographyInventory.open();
} }
public static final class BuilderImpl
extends AbstractSingleWindow.AbstractBuilder<CartographyWindow, Player, CartographyWindow.Builder.Single>
implements CartographyWindow.Builder.Single
{
@Override
public @NotNull CartographyWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new CartographySingleWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
}
} }

@ -1,4 +1,4 @@
package xyz.xenondevs.invui.window.impl; package xyz.xenondevs.invui.window;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -13,14 +13,11 @@ import xyz.xenondevs.inventoryaccess.map.MapIcon;
import xyz.xenondevs.inventoryaccess.map.MapPatch; import xyz.xenondevs.inventoryaccess.map.MapPatch;
import xyz.xenondevs.invui.gui.AbstractGui; import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.impl.NormalGuiImpl;
import xyz.xenondevs.invui.util.MathUtils; import xyz.xenondevs.invui.util.MathUtils;
import xyz.xenondevs.invui.window.AbstractSplitWindow;
import xyz.xenondevs.invui.window.CartographyWindow;
import java.util.List; import java.util.List;
public final class CartographySplitWindowImpl extends AbstractSplitWindow implements CartographyWindow { final class CartographySplitWindowImpl extends AbstractSplitWindow implements CartographyWindow {
private final CartographyInventory cartographyInventory; private final CartographyInventory cartographyInventory;
private int mapId; private int mapId;
@ -43,14 +40,13 @@ public final class CartographySplitWindowImpl extends AbstractSplitWindow implem
register(); register();
} }
@SuppressWarnings("deprecation")
private static AbstractGui createWrappingGui(Gui upperGui) { private static AbstractGui createWrappingGui(Gui upperGui) {
if (upperGui.getWidth() != 2 || upperGui.getHeight() != 1) if (upperGui.getWidth() != 2 || upperGui.getHeight() != 1)
throw new IllegalArgumentException("Gui has to be 2x1"); throw new IllegalArgumentException("Gui has to be 2x1");
NormalGuiImpl wrapperGui = new NormalGuiImpl(3, 1); Gui wrapperGui = Gui.empty(3, 1);
wrapperGui.fillRectangle(1, 0, upperGui, true); wrapperGui.fillRectangle(1, 0, upperGui, true);
return wrapperGui; return (AbstractGui) wrapperGui;
} }
@Override @Override
@ -80,4 +76,33 @@ public final class CartographySplitWindowImpl extends AbstractSplitWindow implem
cartographyInventory.open(); cartographyInventory.open();
} }
public static final class BuilderImpl
extends AbstractSplitWindow.AbstractBuilder<CartographyWindow, Player, CartographyWindow.Builder.Split>
implements CartographyWindow.Builder.Split
{
@Override
public @NotNull CartographyWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (upperGuiSupplier == null)
throw new IllegalStateException("Upper Gui is not defined.");
var window = new CartographySplitWindowImpl(
viewer,
title,
(AbstractGui) upperGuiSupplier.get(),
(AbstractGui) lowerGuiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
}
} }

@ -1,13 +1,36 @@
package xyz.xenondevs.invui.window; package xyz.xenondevs.invui.window;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.map.MapIcon; import xyz.xenondevs.inventoryaccess.map.MapIcon;
import xyz.xenondevs.inventoryaccess.map.MapPatch; import xyz.xenondevs.inventoryaccess.map.MapPatch;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
public interface CartographyWindow extends Window { public interface CartographyWindow extends Window {
static @NotNull Builder.Single single() {
return new CartographySingleWindowImpl.BuilderImpl();
}
static @NotNull CartographyWindow single(@NotNull Consumer<Builder.@NotNull Single> consumer) {
Builder.Single builder = single();
consumer.accept(builder);
return builder.build();
}
static @NotNull Builder.Split split() {
return new CartographySplitWindowImpl.BuilderImpl();
}
static @NotNull CartographyWindow split(@NotNull Consumer<Builder.@NotNull Split> consumer) {
Builder.Split builder = split();
consumer.accept(builder);
return builder.build();
}
void updateMap(@Nullable MapPatch patch, @Nullable List<MapIcon> icons); void updateMap(@Nullable MapPatch patch, @Nullable List<MapIcon> icons);
default void updateMap(@Nullable MapPatch patch) { default void updateMap(@Nullable MapPatch patch) {
@ -20,4 +43,11 @@ public interface CartographyWindow extends Window {
void resetMap(); void resetMap();
interface Builder<S extends Builder<S>> extends Window.Builder<CartographyWindow, Player, S> {
interface Single extends Builder<Single>, Window.Builder.Single<CartographyWindow, Player, Single> {}
interface Split extends Builder<Split>, Window.Builder.Double<CartographyWindow, Player, Split> {}
}
} }

@ -1,4 +1,4 @@
package xyz.xenondevs.invui.window.impl; package xyz.xenondevs.invui.window;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -8,9 +8,8 @@ import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper; import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui; import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.window.AbstractMergedWindow;
public final class NormalMergedWindowImpl extends AbstractMergedWindow { final class NormalMergedWindowImpl extends AbstractMergedWindow {
public NormalMergedWindowImpl( public NormalMergedWindowImpl(
@NotNull Player player, @NotNull Player player,
@ -32,4 +31,30 @@ public final class NormalMergedWindowImpl extends AbstractMergedWindow {
return Bukkit.createInventory(null, gui.getSize() - 36); return Bukkit.createInventory(null, gui.getSize() - 36);
} }
public static final class BuilderImpl
extends AbstractSingleWindow.AbstractBuilder<Window, Player, Window.Builder.Normal.Merged>
implements Window.Builder.Normal.Merged
{
@Override
public @NotNull Window build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new NormalMergedWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
}
} }

@ -0,0 +1,59 @@
package xyz.xenondevs.invui.window;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.util.InventoryUtils;
import java.util.UUID;
final class NormalSingleWindowImpl extends AbstractSingleWindow {
public NormalSingleWindowImpl(
@NotNull UUID viewerUUID,
@Nullable ComponentWrapper title,
@NotNull AbstractGui gui,
boolean closeable,
boolean retain
) {
super(viewerUUID, title, gui, InventoryUtils.createMatchingInventory(gui, ""), true, closeable, retain);
register();
}
public static final class BuilderImpl
extends AbstractSingleWindow.AbstractBuilder<Window, UUID, Window.Builder.Normal.Single>
implements Window.Builder.Normal.Single
{
@Contract("_ -> this")
public BuilderImpl setViewer(@NotNull OfflinePlayer player) {
setViewer(player.getUniqueId());
return this;
}
@Override
public @NotNull Window build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new NormalSingleWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
}
}

@ -0,0 +1,54 @@
package xyz.xenondevs.invui.window;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.util.InventoryUtils;
final class NormalSplitWindowImpl extends AbstractSplitWindow {
public NormalSplitWindowImpl(
@NotNull Player player,
@Nullable ComponentWrapper title,
@NotNull AbstractGui upperGui,
@NotNull AbstractGui lowerGui,
boolean closeable,
boolean retain
) {
super(player, title, upperGui, lowerGui, InventoryUtils.createMatchingInventory(upperGui, ""), true, closeable, retain);
register();
}
public static final class BuilderImpl
extends AbstractSplitWindow.AbstractBuilder<Window, Player, Window.Builder.Normal.Split>
implements Window.Builder.Normal.Split
{
@Override
public @NotNull Window build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (upperGuiSupplier == null)
throw new IllegalStateException("Upper Gui is not defined.");
if (lowerGuiSupplier == null)
throw new IllegalStateException("Lower Gui is not defined.");
var window = new NormalSplitWindowImpl(
viewer,
title,
(AbstractGui) upperGuiSupplier.get(),
(AbstractGui) lowerGuiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
}
}

@ -1,29 +1,93 @@
package xyz.xenondevs.invui.window; package xyz.xenondevs.invui.window;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper; import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.window.builder.WindowType; import xyz.xenondevs.invui.gui.Gui;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Supplier;
/** /**
* A Window is the way to show a player a Gui. Windows can only have one viewer. * A Window is the way to show a player a {@link Gui}. Windows can only have one viewer.
* The default Window implementations can be instantiated using {@link WindowType}. * To create a new {@link Window}, use the builder factory methods {@link Window#single},
* {@link Window#split} and {@link Window#merged}.
* *
* @see WindowType * @see AnvilWindow
* @see AbstractWindow * @see CartographyWindow
* @see AbstractSingleWindow
* @see AbstractDoubleWindow
* @see AbstractSplitWindow
* @see AbstractMergedWindow
*/ */
public interface Window { public interface Window {
/**
* Creates a new {@link Builder.Normal.Single Window Builder} for a normal single window.
*
* @return The new {@link Builder.Normal.Single Window Builder}.
*/
static @NotNull Builder.Normal.Single single() {
return new NormalSingleWindowImpl.BuilderImpl();
}
/**
* Creates a new normal single {@link Window} after configuring a {@link Builder.Normal.Split Window Builder} with the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder.Normal.Split Window Builder}.
* @return The new {@link Window}.
*/
static @NotNull Window single(@NotNull Consumer<Builder.Normal.@NotNull Single> consumer) {
Builder.Normal.Single builder = single();
consumer.accept(builder);
return builder.build();
}
/**
* Creates a new {@link Builder.Normal.Split Window Builder} for a normal split window.
*
* @return The new {@link Builder.Normal.Split Window Builder}.
*/
static @NotNull Builder.Normal.Split split() {
return new NormalSplitWindowImpl.BuilderImpl();
}
/**
* Creates a new normal split {@link Window} after configuring a {@link Builder.Normal.Split Window Builder} with the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder.Normal.Split Window Builder}.
* @return The new {@link Window}.
*/
static @NotNull Window split(@NotNull Consumer<Builder.Normal.@NotNull Split> consumer) {
Builder.Normal.Split builder = split();
consumer.accept(builder);
return builder.build();
}
/**
* Creates a new {@link Builder.Normal.Merged Window Builder} for a normal merged window.
*
* @return The new {@link Builder.Normal.Merged Window Builder}.
*/
static @NotNull Builder.Normal.Merged merged() {
return new NormalMergedWindowImpl.BuilderImpl();
}
/**
* Creates a new normal merged {@link Window} after configuring a {@link Builder.Normal.Merged Window Builder} with the given {@link Consumer}.
*
* @param consumer The {@link Consumer} to configure the {@link Builder.Normal.Merged Window Builder}.
* @return The new {@link Window}.
*/
static @NotNull Window merged(@NotNull Consumer<Builder.Normal.@NotNull Merged> consumer) {
Builder.Normal.Merged builder = merged();
consumer.accept(builder);
return builder.build();
}
/** /**
* Shows the window to the player. * Shows the window to the player.
*/ */
@ -125,4 +189,290 @@ public interface Window {
*/ */
void removeCloseHandler(@NotNull Runnable closeHandler); void removeCloseHandler(@NotNull Runnable closeHandler);
/**
* A {@link Window} builder.
*
* @param <W> The window type
* @param <V> The viewer type
* @param <S> The builder type
*/
interface Builder<W extends Window, V, S extends Builder<W, V, S>> extends Cloneable {
/**
* Sets the viewer of the {@link Window}.
*
* @param viewer The viewer of the {@link Window}
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setViewer(@NotNull V viewer);
/**
* Sets the title of the {@link Window}.
*
* @param title The title of the {@link Window}
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setTitle(@NotNull ComponentWrapper title);
/**
* Sets the title of the {@link Window}.
*
* @param title The title of the {@link Window}
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setTitle(@NotNull BaseComponent @NotNull [] title);
/**
* Sets the title of the {@link Window}.
*
* @param title The title of the {@link Window}
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setTitle(@NotNull String title);
/**
* Configures if the {@link Window} is closeable.
*
* @param closeable If the {@link Window} is closeable
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setCloseable(boolean closeable);
/**
* Configures if the {@link Window} should be retained after it has been closed.
*
* @param retain If the {@link Window} should be retained
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setRetain(boolean retain);
/**
* Sets the close handlers of the {@link Window}.
*
* @param closeHandlers The close handlers of the {@link Window}
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setCloseHandlers(List<Runnable> closeHandlers);
/**
* Adds a close handler to the {@link Window}.
*
* @param closeHandler The close handler to add
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S addCloseHandler(Runnable closeHandler);
/**
* Sets the modifiers of the {@link Window}.
*
* @param modifiers The modifiers of the {@link Window}
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S setModifiers(List<Consumer<Window>> modifiers);
/**
* Adds a modifier to the {@link Window}.
*
* @param modifier The modifier to add
* @return This {@link Builder Window Builder}
*/
@Contract("_ -> this")
S addModifier(Consumer<Window> modifier);
/**
* Builds the {@link Window}.
*
* @return The built {@link Window}
*/
@Contract("-> new")
@NotNull W build();
/**
* Clones the {@link Builder Window Builder}.
*
* @return The cloned {@link Builder Window Builder}
*/
@Contract("-> new")
@NotNull S clone();
/**
* A single {@link Window} builder. Single Windows only have on {@link Gui}.
*
* @param <W> The window type
* @param <V> The viewer type
* @param <S> The builder type
*
* @see Window.Builder.Normal.Single
* @see Window.Builder.Normal.Merged
* @see AnvilWindow.Builder.Single
* @see CartographyWindow.Builder.Single
*/
interface Single<W extends Window, V, S extends Single<W, V, S>> extends Builder<W, V, S> {
/**
* Sets the {@link Gui} of the {@link Window}.
*
* @param gui The {@link Gui} of the {@link Window}
* @return This {@link Single Window Builder}
*/
@Contract("_ -> this")
S setGui(@NotNull Gui gui);
/**
* Sets the {@link Gui.Builder} for this {@link Single Window Builder}.
* The {@link Gui.Builder} will be called every time a new {@link Window} is created using this builder.
*
* @param builder The {@link Gui.Builder} for this {@link Single Window Builder}
* @return This {@link Single Window Builder}
*/
@Contract("_ -> this")
S setGui(@NotNull Gui.Builder<?, ?> builder);
/**
* Sets the {@link Gui} {@link Supplier} for this {@link Single Window Builder}.
* The {@link Supplier} will be called every time a new {@link Window} is created using this builder.
*
* @param guiSupplier The {@link Gui} {@link Supplier}
* @return This {@link Single Window Builder}
*/
@Contract("_ -> this")
S setGui(@NotNull Supplier<Gui> guiSupplier);
}
/**
* A double {@link Window} builder. Double Windows have two {@link Gui Guis}.
*
* @param <W> The window type
* @param <V> The viewer type
* @param <S> The builder type
*
* @see Window.Builder.Normal.Split
* @see AnvilWindow.Builder.Split
* @see CartographyWindow.Builder.Split
*/
interface Double<W extends Window, V, S extends Builder.Double<W, V, S>> extends Builder<W, V, S> {
/**
* Sets the upper {@link Gui} of the {@link Window}.
*
* @param gui The upper {@link Gui} of the {@link Window}
* @return This {@link Double Window Builder}
*/
@Contract("_ -> this")
S setUpperGui(@NotNull Gui gui);
/**
* Sets the {@link Gui.Builder} for the upper {@link Gui} of this {@link Double Window Builder}.
* The {@link Gui.Builder} will be called every time a new {@link Window} is created using this builder.
*
* @param builder The {@link Gui.Builder} for the upper {@link Gui} of this {@link Double Window Builder}
* @return This {@link Double Window Builder}
*/
@Contract("_ -> this")
S setUpperGui(@NotNull Gui.Builder<?, ?> builder);
/**
* Sets the {@link Gui} {@link Supplier} for the upper {@link Gui} of this {@link Double Window Builder}.
* The {@link Supplier} will be called every time a new {@link Window} is created using this builder.
*
* @param guiSupplier The {@link Gui} {@link Supplier} for the upper {@link Gui} of this {@link Double Window Builder}
* @return This {@link Double Window Builder}
*/
@Contract("_ -> this")
S setUpperGui(@NotNull Supplier<Gui> guiSupplier);
/**
* Sets the lower {@link Gui} of the {@link Window}.
*
* @param gui The lower {@link Gui} of the {@link Window}
* @return This {@link Double Window Builder}
*/
@Contract("_ -> this")
S setLowerGui(@NotNull Gui gui);
/**
* Sets the {@link Gui.Builder} for the lower {@link Gui} of this {@link Double Window Builder}.
* The {@link Gui.Builder} will be called every time a new {@link Window} is created using this builder.
*
* @param builder The {@link Gui.Builder} for the lower {@link Gui} of this {@link Double Window Builder}
* @return This {@link Double Window Builder}
*/
@Contract("_ -> this")
S setLowerGui(@NotNull Gui.Builder<?, ?> builder);
/**
* Sets the {@link Gui} {@link Supplier} for the lower {@link Gui} of this {@link Double Window Builder}.
* The {@link Supplier} will be called every time a new {@link Window} is created using this builder.
*
* @param guiSupplier The {@link Gui} {@link Supplier} for the lower {@link Gui} of this {@link Double Window Builder}
* @return This {@link Double Window Builder}
*/
@Contract("_ -> this")
S setLowerGui(@NotNull Supplier<Gui> guiSupplier);
}
/**
* A normal {@link Window} builder for {@link Window Windows} of inventories with no special functionality, such
* as chests, hoppers and droppers.
*
* @param <V> The viewer type
* @param <S> The builder type
*
* @see AnvilWindow.Builder
* @see CartographyWindow.Builder
*/
interface Normal<V, S extends Normal<V, S>> extends Builder<Window, V, S> {
/**
* A normal single {@link Window} builder. Combines both {@link Builder.Single} and {@link Builder.Normal}
* for a normal {@link Window} with only one {@link Gui} that does not access the {@link Player Player's} inventory.
*
* @see AnvilWindow.Builder.Single
* @see CartographyWindow.Builder.Single
*/
interface Single extends Builder.Normal<UUID, Single>, Builder.Single<Window, UUID, Single> {
/**
* Sets the viewer of the {@link Window}.
*
* @param viewer The viewer of the {@link Window}
* @return This {@link Normal.Single Window Builder}
*/
@Contract("_ -> this")
Normal.Single setViewer(@NotNull OfflinePlayer viewer);
}
/**
* A normal split {@link Window} builder. Combines both {@link Builder.Double} and {@link Builder.Normal}
* for a normal {@link Window} with two {@link Gui Guis}, where the lower {@link Gui} is used to fill the
* {@link Player Player's} inventory.
*
* @see AnvilWindow.Builder.Split
* @see CartographyWindow.Builder.Split
*/
interface Split extends Builder.Normal<Player, Split>, Builder.Double<Window, Player, Split> {}
/**
* A normal merged {@link Window} builder. Combines both {@link Builder.Single} and {@link Builder.Normal}
* for a normal {@link Window} with one {@link Gui}, which fills both the upper inventory and the
* {@link Player Player's} inventory.
*/
interface Merged extends Builder.Normal<Player, Merged>, Builder.Single<Window, Player, Merged> {}
}
}
} }

@ -1,33 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.builder.GuiBuilder;
import xyz.xenondevs.invui.window.Window;
import java.util.function.Supplier;
public abstract class AbstractSingleWindowBuilder<W extends Window, V, S extends AbstractSingleWindowBuilder<W, V, S>> extends AbstractWindowBuilder<W, V, S> {
protected Supplier<Gui> guiSupplier;
@Contract("_ -> this")
public S setGui(@NotNull Supplier<Gui> guiSupplier) {
this.guiSupplier = guiSupplier;
return getThis();
}
@Contract("_ -> this")
public S setGui(@NotNull Gui gui) {
this.guiSupplier = () -> gui;
return getThis();
}
@Contract("_ -> this")
public S setGui(@NotNull GuiBuilder<?> builder) {
this.guiSupplier = builder::build;
return getThis();
}
}

@ -1,52 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.Gui;
import xyz.xenondevs.invui.gui.builder.GuiBuilder;
import xyz.xenondevs.invui.window.Window;
import java.util.function.Supplier;
public abstract class AbstractSplitWindowBuilder<W extends Window, V, S extends AbstractSplitWindowBuilder<W, V, S>> extends AbstractWindowBuilder<W, V, S> {
protected Supplier<Gui> upperGuiSupplier;
protected Supplier<Gui> lowerGuiSupplier;
@Contract("_ -> this")
public S setUpperGui(@NotNull Supplier<Gui> guiSupplier) {
this.upperGuiSupplier = guiSupplier;
return getThis();
}
@Contract("_ -> this")
public S setUpperGui(@NotNull Gui gui) {
this.upperGuiSupplier = () -> gui;
return getThis();
}
@Contract("_ -> this")
public S setUpperGui(@NotNull GuiBuilder<?> builder) {
this.upperGuiSupplier = builder::build;
return getThis();
}
@Contract("_ -> this")
public S setLowerGui(@NotNull Supplier<Gui> guiSupplier) {
this.lowerGuiSupplier = guiSupplier;
return getThis();
}
@Contract("_ -> this")
public S setLowerGui(@NotNull Gui gui) {
this.lowerGuiSupplier = () -> gui;
return getThis();
}
@Contract("_ -> this")
public S setLowerGui(@NotNull GuiBuilder<?> builder) {
this.lowerGuiSupplier = builder::build;
return getThis();
}
}

@ -1,118 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.inventoryaccess.component.BaseComponentWrapper;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.window.Window;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public abstract class AbstractWindowBuilder<W extends Window, V, S extends AbstractWindowBuilder<W, V, S>> implements WindowBuilder<W> {
protected V viewer;
protected ComponentWrapper title;
protected boolean closeable = true;
protected boolean retain = false;
protected List<Runnable> closeHandlers;
protected List<Consumer<Window>> modifiers;
@Contract("_ -> this")
public S setViewer(@NotNull V viewer) {
this.viewer = viewer;
return getThis();
}
@Contract("_ -> this")
public S setTitle(@NotNull ComponentWrapper title) {
this.title = title;
return getThis();
}
@Contract("_ -> this")
public S setTitle(@NotNull BaseComponent @NotNull [] title) {
this.title = new BaseComponentWrapper(title);
return getThis();
}
@Contract("_ -> this")
public S setTitle(@NotNull String title) {
this.title = new BaseComponentWrapper(TextComponent.fromLegacyText(title));
return getThis();
}
@Contract("_ -> this")
public S setCloseable(boolean closeable) {
this.closeable = closeable;
return getThis();
}
@Contract("_ -> this")
public S setRetain(boolean retain) {
this.retain = retain;
return getThis();
}
@Contract("_ -> this")
public S setCloseHandlers(List<Runnable> closeHandlers) {
this.closeHandlers = closeHandlers;
return getThis();
}
@Contract("_ -> this")
public S addCloseHandler(Runnable closeHandler) {
if (closeHandlers == null)
closeHandlers = new ArrayList<>();
closeHandlers.add(closeHandler);
return getThis();
}
@Contract("_ -> this")
public S setModifiers(List<Consumer<Window>> modifiers) {
this.modifiers = modifiers;
return getThis();
}
@Contract("_ -> this")
public S addModifier(Consumer<Window> modifier) {
if (modifiers == null)
modifiers = new ArrayList<>();
modifiers.add(modifier);
return getThis();
}
protected void applyModifiers(W window) {
if (closeHandlers != null)
window.setCloseHandlers(closeHandlers);
if (modifiers != null)
modifiers.forEach(modifier -> modifier.accept(window));
}
@SuppressWarnings("unchecked")
@Override
public @NotNull AbstractWindowBuilder<W, V, S> clone() {
try {
var clone = (AbstractWindowBuilder<W, V, S>) super.clone();
if (title != null)
clone.title = title.clone();
if (closeHandlers != null)
clone.closeHandlers = new ArrayList<>(closeHandlers);
if (modifiers != null)
clone.modifiers = new ArrayList<>(modifiers);
return clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
@Contract(value = "-> this", pure = true)
protected abstract S getThis();
}

@ -1,67 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.AnvilWindow;
import xyz.xenondevs.invui.window.impl.AnvilSingleWindowImpl;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public final class AnvilSingleWindowBuilder extends AbstractSingleWindowBuilder<AnvilWindow, Player, AnvilSingleWindowBuilder> {
private List<Consumer<String>> renameHandlers;
AnvilSingleWindowBuilder() {
}
@Contract("_ -> this")
public AnvilSingleWindowBuilder setRenameHandlers(@NotNull List<@NotNull Consumer<String>> renameHandlers) {
this.renameHandlers = renameHandlers;
return this;
}
@Contract("_ -> this")
public AnvilSingleWindowBuilder addRenameHandler(@NotNull Consumer<String> renameHandler) {
if (renameHandlers == null)
renameHandlers = new ArrayList<>();
renameHandlers.add(renameHandler);
return this;
}
@Override
public @NotNull AnvilWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new AnvilSingleWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
renameHandlers,
closeable,
retain
);
applyModifiers(window);
return window;
}
@Override
protected AnvilSingleWindowBuilder getThis() {
return null;
}
@Override
public @NotNull AnvilSingleWindowBuilder clone() {
return (AnvilSingleWindowBuilder) super.clone();
}
}

@ -1,70 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.AnvilWindow;
import xyz.xenondevs.invui.window.impl.AnvilSplitWindowImpl;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public final class AnvilSplitWindowBuilder extends AbstractSplitWindowBuilder<AnvilWindow, Player, AnvilSplitWindowBuilder> {
private List<Consumer<String>> renameHandlers;
AnvilSplitWindowBuilder() {
}
@Contract("_ -> this")
public AnvilSplitWindowBuilder setRenameHandlers(@NotNull List<@NotNull Consumer<String>> renameHandlers) {
this.renameHandlers = renameHandlers;
return this;
}
@Contract("_ -> this")
public AnvilSplitWindowBuilder addRenameHandler(@NotNull Consumer<String> renameHandler) {
if (renameHandlers == null)
renameHandlers = new ArrayList<>();
renameHandlers.add(renameHandler);
return this;
}
@Override
public @NotNull AnvilWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (upperGuiSupplier == null)
throw new IllegalStateException("Upper Gui is not defined.");
if (lowerGuiSupplier == null)
throw new IllegalStateException("Lower Gui is not defined.");
var window = new AnvilSplitWindowImpl(
viewer,
title,
(AbstractGui) upperGuiSupplier.get(),
(AbstractGui) lowerGuiSupplier.get(),
renameHandlers,
closeable,
retain
);
applyModifiers(window);
return window;
}
@Override
protected AnvilSplitWindowBuilder getThis() {
return this;
}
@Override
public @NotNull AnvilSplitWindowBuilder clone() {
return (AnvilSplitWindowBuilder) super.clone();
}
}

@ -1,44 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.CartographyWindow;
import xyz.xenondevs.invui.window.impl.CartographySingleWindowImpl;
public final class CartographySingleWindowBuilder extends AbstractSingleWindowBuilder<CartographyWindow, Player, CartographySingleWindowBuilder> {
CartographySingleWindowBuilder() {
}
@Override
public @NotNull CartographyWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new CartographySingleWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
@Override
protected CartographySingleWindowBuilder getThis() {
return this;
}
@Override
public @NotNull CartographySingleWindowBuilder clone() {
return (CartographySingleWindowBuilder) super.clone();
}
}

@ -1,45 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.CartographyWindow;
import xyz.xenondevs.invui.window.impl.CartographySplitWindowImpl;
public final class CartographySplitWindowBuilder extends AbstractSplitWindowBuilder<CartographyWindow, Player, CartographySplitWindowBuilder> {
CartographySplitWindowBuilder() {
}
@Override
public @NotNull CartographyWindow build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (upperGuiSupplier == null)
throw new IllegalStateException("Upper Gui is not defined.");
var window = new CartographySplitWindowImpl(
viewer,
title,
(AbstractGui) upperGuiSupplier.get(),
(AbstractGui) lowerGuiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
@Override
protected CartographySplitWindowBuilder getThis() {
return this;
}
@Override
public @NotNull CartographySplitWindowBuilder clone() {
return (CartographySplitWindowBuilder) super.clone();
}
}

@ -1,44 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.Window;
import xyz.xenondevs.invui.window.impl.NormalMergedWindowImpl;
public final class NormalMergedWindowBuilder extends AbstractSingleWindowBuilder<Window, Player, NormalMergedWindowBuilder> {
NormalMergedWindowBuilder() {
}
@Override
public @NotNull Window build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new NormalMergedWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
@Override
protected NormalMergedWindowBuilder getThis() {
return this;
}
@Override
public @NotNull NormalMergedWindowBuilder clone() {
return (NormalMergedWindowBuilder) super.clone();
}
}

@ -1,53 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.bukkit.OfflinePlayer;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.Window;
import xyz.xenondevs.invui.window.impl.NormalSingleWindowImpl;
import java.util.UUID;
public final class NormalSingleWindowBuilder extends AbstractSingleWindowBuilder<Window, UUID, NormalSingleWindowBuilder> {
NormalSingleWindowBuilder() {
}
@Contract("_ -> this")
public NormalSingleWindowBuilder setViewer(@NotNull OfflinePlayer player) {
setViewer(player.getUniqueId());
return this;
}
@Override
public @NotNull Window build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (guiSupplier == null)
throw new IllegalStateException("Gui is not defined.");
var window = new NormalSingleWindowImpl(
viewer,
title,
(AbstractGui) guiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
@Override
protected NormalSingleWindowBuilder getThis() {
return this;
}
@Override
public @NotNull NormalSingleWindowBuilder clone() {
return (NormalSingleWindowBuilder) super.clone();
}
}

@ -1,47 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.Window;
import xyz.xenondevs.invui.window.impl.NormalSplitWindowImpl;
public final class NormalSplitWindowBuilder extends AbstractSplitWindowBuilder<Window, Player, NormalSplitWindowBuilder> {
NormalSplitWindowBuilder() {
}
@Override
public @NotNull Window build() {
if (viewer == null)
throw new IllegalStateException("Viewer is not defined.");
if (upperGuiSupplier == null)
throw new IllegalStateException("Upper Gui is not defined.");
if (lowerGuiSupplier == null)
throw new IllegalStateException("Lower Gui is not defined.");
var window = new NormalSplitWindowImpl(
viewer,
title,
(AbstractGui) upperGuiSupplier.get(),
(AbstractGui) lowerGuiSupplier.get(),
closeable,
retain
);
applyModifiers(window);
return window;
}
@Override
protected NormalSplitWindowBuilder getThis() {
return this;
}
@Override
public @NotNull NormalSplitWindowBuilder clone() {
return (NormalSplitWindowBuilder) super.clone();
}
}

@ -1,15 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.window.Window;
public interface WindowBuilder<W extends Window> extends Cloneable {
@Contract("-> new")
@NotNull W build();
@Contract("-> new")
@NotNull WindowBuilder<W> clone();
}

@ -1,39 +0,0 @@
package xyz.xenondevs.invui.window.builder;
import org.jetbrains.annotations.NotNull;
import xyz.xenondevs.invui.window.AnvilWindow;
import xyz.xenondevs.invui.window.CartographyWindow;
import xyz.xenondevs.invui.window.Window;
import java.util.function.Consumer;
public interface WindowType<W extends Window, B extends WindowBuilder<W>> {
WindowType<Window, NormalSingleWindowBuilder> NORMAL = NormalSingleWindowBuilder::new;
WindowType<Window, NormalMergedWindowBuilder> NORMAL_MERGED = NormalMergedWindowBuilder::new;
WindowType<Window, NormalSplitWindowBuilder> NORMAL_SPLIT = NormalSplitWindowBuilder::new;
WindowType<AnvilWindow, AnvilSingleWindowBuilder> ANVIL = AnvilSingleWindowBuilder::new;
WindowType<AnvilWindow, AnvilSplitWindowBuilder> ANVIL_SPLIT = AnvilSplitWindowBuilder::new;
WindowType<CartographyWindow, CartographySingleWindowBuilder> CARTOGRAPHY = CartographySingleWindowBuilder::new;
WindowType<CartographyWindow, CartographySplitWindowBuilder> CARTOGRAPHY_SPLIT = CartographySplitWindowBuilder::new;
/**
* Creates a new {@link WindowBuilder} for this {@link WindowType}.
*
* @return The new {@link WindowBuilder}.
*/
@NotNull B builder();
/**
* Creates a new {@link Window} after modifying the {@link WindowBuilder} with the given {@link Consumer}.
*
* @param builderConsumer The {@link Consumer} which modifies the {@link WindowBuilder}.
* @return The new {@link Window}.
*/
default @NotNull W createWindow(Consumer<B> builderConsumer) {
B builder = builder();
builderConsumer.accept(builder);
return builder.build();
}
}

@ -1,58 +0,0 @@
package xyz.xenondevs.invui.window.impl;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.InventoryAccess;
import xyz.xenondevs.inventoryaccess.abstraction.inventory.AnvilInventory;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.window.AbstractSplitWindow;
import xyz.xenondevs.invui.window.AnvilWindow;
import java.util.List;
import java.util.function.Consumer;
public final class AnvilSplitWindowImpl extends AbstractSplitWindow implements AnvilWindow {
private final AnvilInventory anvilInventory;
public AnvilSplitWindowImpl(
@NotNull Player player,
@Nullable ComponentWrapper title,
@NotNull AbstractGui upperGui,
@NotNull AbstractGui lowerGui,
@Nullable List<@NotNull Consumer<@NotNull String>> renameHandlers,
boolean closeable,
boolean retain
) {
super(player, title, upperGui, lowerGui, null, false, closeable, retain);
anvilInventory = InventoryAccess.createAnvilInventory(player, title, renameHandlers);
upperInventory = anvilInventory.getBukkitInventory();
initUpperItems();
register();
}
@Override
protected void setUpperInvItem(int slot, ItemStack itemStack) {
anvilInventory.setItem(slot, itemStack);
}
@Override
public void show() {
if (isRemoved()) throw new IllegalStateException("The Window has already been closed.");
Player viewer = getViewer();
if (viewer == null) throw new IllegalStateException("The player is not online.");
anvilInventory.open();
}
@Override
public String getRenameText() {
return anvilInventory.getRenameText();
}
}

@ -1,25 +0,0 @@
package xyz.xenondevs.invui.window.impl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.util.InventoryUtils;
import xyz.xenondevs.invui.window.AbstractSingleWindow;
import java.util.UUID;
public final class NormalSingleWindowImpl extends AbstractSingleWindow {
public NormalSingleWindowImpl(
@NotNull UUID viewerUUID,
@Nullable ComponentWrapper title,
@NotNull AbstractGui gui,
boolean closeable,
boolean retain
) {
super(viewerUUID, title, gui, InventoryUtils.createMatchingInventory(gui, ""), true, closeable, retain);
register();
}
}

@ -1,25 +0,0 @@
package xyz.xenondevs.invui.window.impl;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import xyz.xenondevs.inventoryaccess.component.ComponentWrapper;
import xyz.xenondevs.invui.gui.AbstractGui;
import xyz.xenondevs.invui.util.InventoryUtils;
import xyz.xenondevs.invui.window.AbstractSplitWindow;
public final class NormalSplitWindowImpl extends AbstractSplitWindow {
public NormalSplitWindowImpl(
@NotNull Player player,
@Nullable ComponentWrapper title,
@NotNull AbstractGui upperGui,
@NotNull AbstractGui lowerGui,
boolean closeable,
boolean retain
) {
super(player, title, upperGui, lowerGui, InventoryUtils.createMatchingInventory(upperGui, ""), true, closeable, retain);
register();
}
}