/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.views.menu; import com.jcwhatever.nucleus.utils.CollectionUtils; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.items.ItemStackMatcher; import com.jcwhatever.nucleus.views.chest.ChestEventAction; import com.jcwhatever.nucleus.views.chest.ChestEventInfo; import com.jcwhatever.nucleus.views.chest.ChestView; import com.jcwhatever.nucleus.views.chest.InventoryItemAction.InventoryPosition; import org.bukkit.inventory.Inventory; import org.bukkit.plugin.Plugin; import java.util.List; import javax.annotation.Nullable; /** * Abstract implementation of a {@link ChestView} for use as a menu. */ public abstract class MenuView extends ChestView { private MenuInventory _inventory; /** * Constructor. * * @param plugin The owning plugin. * @param matcher An item stack matcher. */ protected MenuView(Plugin plugin, @Nullable ItemStackMatcher matcher) { super(plugin, matcher); } /** * Constructor. * * @param plugin The owning plugin. * @param inventory The menu inventory. * @param matcher An item stack matcher. */ protected MenuView(Plugin plugin, MenuInventory inventory, @Nullable ItemStackMatcher matcher) { super(plugin, inventory, matcher); } /** * Get the currently registered {@link MenuItem}'s. */ public List<MenuItem> getMenuItems() { if (_inventory == null) return CollectionUtils.unmodifiableList(MenuItem.class); return CollectionUtils.unmodifiableList(_inventory.getMenuItems()); } /** * Get the registered {@link MenuItem} at the specified * slot index. * * @param slot The slot index. * * @return Null if not found. */ @Nullable public MenuItem getMenuItem(int slot) { return _inventory.getMenuItem(slot); } /** * Remove a menu item from the view. * * @param menuItem The menu item to remove. */ public void removeMenuItem(MenuItem menuItem) { PreCon.notNull(menuItem); MenuItem item = _inventory.getMenuItem(menuItem.getSlot()); if (!menuItem.equals(item)) return; _inventory.setItem(menuItem.getSlot(), null); Inventory inventory = getInventory(); if (inventory == null) return; menuItem.setVisible(this, false); } /** * Set a menu item into the view inventory and register it. * * @param menuItem The menu item to set. */ public void setMenuItem(MenuItem menuItem) { PreCon.notNull(menuItem); menuItem.setVisible(this, true); } /** * Create the inventory needed by the {@link ChestView} super type. */ @Override protected Inventory createInventory() { List<MenuItem> menuItems = createMenuItems(); if (menuItems.size() > MAX_SLOTS) throw new RuntimeException("The number of menu items cannot be more than " + MAX_SLOTS + '.'); int maxSlots = getSlotsRequired(menuItems); _inventory = new MenuInventory(getPlayer(), maxSlots, getTitle()); for (MenuItem item : menuItems) { //item.set(this); _inventory.setItem(item.getSlot(), item); } return _inventory; } /** * Deny placing items into the menu. */ @Override protected ChestEventAction onItemsPlaced(ChestEventInfo eventInfo) { return ChestEventAction.DENY; } /** * Deny dropping items from the menu. */ @Override protected ChestEventAction onItemsDropped(ChestEventInfo eventInfo) { return ChestEventAction.DENY; } /** * Deny picking up items from the menu. Detect clicks on menu items. */ @Override protected ChestEventAction onItemsPickup(ChestEventInfo eventInfo) { if (eventInfo.getInventoryPosition() == InventoryPosition.TOP) { MenuItem menuItem = _inventory.getMenuItem(eventInfo.getSlot()); if (menuItem != null && menuItem.isVisible(this)) { List<Runnable> clickCallbacks = menuItem.getOnClick(); for (Runnable onClick : clickCallbacks) { onClick.run(); } onItemSelect(menuItem); } } return ChestEventAction.DENY; } /** * Get the number of slots needed for the {@link Inventory} instance. */ protected int getSlotsRequired(List<MenuItem> menuItems) { int maxSlot = menuItems.size(); for (MenuItem menuItem: menuItems) { if (menuItem.getSlot() > maxSlot) { maxSlot = menuItem.getSlot(); } } int rows = (int) Math.ceil((double)maxSlot / ROW_SIZE); return Math.max(rows * ROW_SIZE, ROW_SIZE); } /** * Invoked to get a list of {@link MenuItem}'s to initially register and * fill the {@link org.bukkit.inventory.Inventory} after it is created. */ protected abstract List<MenuItem> createMenuItems(); /** * Invoked when a menu item in the inventory view is clicked by the player. * * @param menuItem The clicked menu item. */ protected abstract void onItemSelect(MenuItem menuItem); }