Added menu pagination

This commit is contained in:
Auxilor
2022-09-29 17:17:13 +01:00
parent 97adae7b32
commit 40b4c26e0f
11 changed files with 336 additions and 34 deletions

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.gui;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.menu.MenuBuilder;
import com.willfp.eco.core.gui.slot.SlotBuilder;
import com.willfp.eco.core.gui.slot.functional.SlotProvider;
@@ -21,6 +22,7 @@ public interface GUIFactory {
* @param provider The provider.
* @return The builder.
*/
@NotNull
SlotBuilder createSlotBuilder(@NotNull SlotProvider provider);
/**
@@ -29,5 +31,17 @@ public interface GUIFactory {
* @param rows The amount of rows.
* @return The builder.
*/
@NotNull
MenuBuilder createMenuBuilder(int rows);
/**
* Combine the state of two menus together.
*
* @param base The base menu.
* @param additional The additional state.
* @return The menu.
*/
@NotNull
Menu blendMenuState(@NotNull Menu base,
@NotNull Menu additional);
}

View File

@@ -1,11 +1,8 @@
package com.willfp.eco.core.gui.component;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.FillerSlot;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,9 +35,9 @@ public interface GUIComponent {
* @return The slot, or null if no slot at the location.
*/
@Nullable
default Slot getSlotAt(int row,
int column) {
return new FillerSlot(new ItemStack(Material.AIR));
default Slot getSlotAt(final int row,
final int column) {
return null;
}
/**
@@ -58,10 +55,10 @@ public interface GUIComponent {
* @return The slot, or null if no slot at the location.
*/
@Nullable
default Slot getSlotAt(int row,
int column,
@NotNull Player player,
@NotNull Menu menu) {
default Slot getSlotAt(final int row,
final int column,
@NotNull final Player player,
@NotNull final Menu menu) {
return getSlotAt(row, column);
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.eco.core.gui.menu;
import com.willfp.eco.core.gui.component.GUIComponent;
import com.willfp.eco.core.gui.page.Page;
import com.willfp.eco.core.gui.slot.FillerMask;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
@@ -9,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Builder to create menus.
@@ -70,17 +72,47 @@ public interface MenuBuilder {
* @param mask The mask.
* @return The builder.
*/
default MenuBuilder setMask(@NotNull FillerMask mask) {
default MenuBuilder setMask(@NotNull final FillerMask mask) {
return this.addComponent(0, 0, mask);
}
/**
* Add a page.
*
* @param page The page.
* @return The builder.
*/
default MenuBuilder addPage(@NotNull final Page page) {
return this.addComponent(0, 0, page);
}
/**
* Set the max pages.
*
* @param pages The max pages.
* @return The builder.
*/
default MenuBuilder maxPages(final int pages) {
return this.maxPages(player -> pages);
}
/**
* Set the max pages dynamically for a player.
*
* @param pages The max pages.
* @return The builder.
*/
default MenuBuilder maxPages(@NotNull final Function<Player, Integer> pages) {
return onOpen((player, menu) -> menu.addState(player, Page.MAX_PAGE_KEY, pages.apply(player)));
}
/**
* Set the menu close handler.
*
* @param action The handler.
* @return The builder.
*/
default MenuBuilder onClose(@NotNull Consumer<InventoryCloseEvent> action) {
default MenuBuilder onClose(@NotNull final Consumer<InventoryCloseEvent> action) {
return this.onClose((event, menu) -> action.accept(event));
}

View File

@@ -0,0 +1,115 @@
package com.willfp.eco.core.gui.page;
import com.willfp.eco.core.Eco;
import com.willfp.eco.core.gui.component.GUIComponent;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
/**
* A page is a component representing another menu.
* This allows full component support in pagination.
*/
public final class Page implements GUIComponent {
/**
* The Menu state key for the current page.
*/
public static final String PAGE_KEY = "page";
/**
* The Menu state key for the amount of pages.
*/
public static final String MAX_PAGE_KEY = "max_page";
/**
* The page number.
*/
private final int pageNumber;
/**
* The base menu.
*/
private final Menu page;
/**
* The delegate menu.
*/
private Menu delegate = null;
/**
* Create a new page.
*
* @param pageNumber The page number.
* @param page The base menu.
*/
public Page(final int pageNumber,
@NotNull final Menu page) {
this.pageNumber = pageNumber;
this.page = page;
}
/**
* Get the current page number.
*
* @return The page number.
*/
public int getPageNumber() {
return this.pageNumber;
}
@Override
public @Nullable Slot getSlotAt(final int row,
final int column,
@NotNull final Player player,
@NotNull final Menu menu) {
if (getPage(player, menu) != pageNumber) {
return null;
}
if (delegate == null) {
delegate = Eco.getHandler().getGUIFactory().blendMenuState(page, menu);
}
return page.getSlot(row, column, player, delegate);
}
@Override
public int getRows() {
return page.getRows();
}
@Override
public int getColumns() {
return 9;
}
/**
* Get the page.
*
* @param player The player.
* @param menu The menu.
* @return The page.
*/
public static int getPage(@NotNull final Player player,
@NotNull final Menu menu) {
Integer pageState = menu.getState(player, Page.PAGE_KEY);
return Objects.requireNonNullElse(pageState, 1);
}
/**
* Get the page.
*
* @param player The player.
* @param menu The menu.
* @return The page.
*/
public static int getMaxPage(@NotNull final Player player,
@NotNull final Menu menu) {
Integer pageState = menu.getState(player, Page.MAX_PAGE_KEY);
return Objects.requireNonNullElse(pageState, Integer.MAX_VALUE);
}
}

View File

@@ -0,0 +1,116 @@
package com.willfp.eco.core.gui.page;
import com.willfp.eco.core.gui.component.GUIComponent;
import com.willfp.eco.core.gui.menu.Menu;
import com.willfp.eco.core.gui.slot.Slot;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A slot loaded in from config.
*/
public final class PageChanger implements GUIComponent {
/**
* The slot to be shown.
*/
private final Slot slot;
/**
* The direction to turn the page.
*/
private final Direction direction;
/**
* Create a new page change slot.
*
* @param direction The direction.
*/
public PageChanger(@NotNull final ItemStack itemStack,
@NotNull final Direction direction) {
this.direction = direction;
slot = Slot.builder(itemStack)
.onLeftClick((event, slot, menu) -> {
Player player = (Player) event.getWhoClicked();
int page = Page.getPage(player, menu);
int newPage = Math.max(
0,
Math.min(
page + direction.getChange(),
Page.getMaxPage(player, menu)
)
);
menu.addState(player, Page.PAGE_KEY, newPage);
})
.build();
}
@Override
public int getRows() {
return 1;
}
@Override
public int getColumns() {
return 1;
}
@Override
public @Nullable Slot getSlotAt(final int row,
final int column,
@NotNull final Player player,
@NotNull final Menu menu) {
int page = Page.getPage(player, menu);
int maxPage = Page.getMaxPage(player, menu);
if (page <= 1 && this.direction == Direction.BACKWARDS) {
return null;
}
if (page >= maxPage - 1 && this.direction == Direction.FORWARDS) {
return null;
}
return slot;
}
/**
* The direction to change the page.
*/
public enum Direction {
/**
* Increment the page by 1.
*/
FORWARDS(1),
/**
* Decrement the page by 1.
*/
BACKWARDS(-1);
/**
* The amount of pages to change by.
*/
private final int change;
/**
* Create a new direction.
*
* @param change The amount of pages to change by.
*/
Direction(final int change) {
this.change = change;
}
/**
* Get the amount of pages to change by.
*
* @return The change.
*/
public int getChange() {
return change;
}
}
}

View File

@@ -4,6 +4,7 @@ package com.willfp.eco.core.gui
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.page.Page
import com.willfp.eco.core.gui.slot.Slot
import com.willfp.eco.core.gui.slot.SlotBuilder
import com.willfp.eco.core.items.TestableItem
@@ -131,6 +132,10 @@ fun MenuBuilder.modify(modifier: (MenuBuilder) -> Unit): MenuBuilder =
fun MenuBuilder.onRender(action: (Player, Menu) -> Unit): MenuBuilder =
this.onRender { a, b -> action(a, b) }
/** @see MenuBuilder.addPage */
fun MenuBuilder.addPage(page: Int, creation: MenuBuilder.() -> MenuBuilder): MenuBuilder =
this.addPage(Page(page, Menu.builder(this.rows).creation().build()))
/** Kotlin builder for menus. */
fun menu(
rows: Int,