Finally finished the 2D Explorer API !

* NEW: ExplorerGui: Implemented 2D data support.
* NEW: ExplorerGui: Implemented retreiving items using coordinates rather than data.
* NEW: ExplorerGui: Added right-click event support.
* NEW: Gui: Added support for dragging events.
* NEW: Maps given to the player now have their attributes hidden.
* BUG: PluginLogger: Fixed exception handling when logging a message with arguments.
This commit is contained in:
Adrien Prokopowicz 2015-08-31 11:36:24 +02:00
parent 0ad44db92b
commit a5449899f1
8 changed files with 320 additions and 35 deletions

View File

@ -57,7 +57,8 @@ abstract public class PluginLogger
static public void log(Level level, String message, Throwable ex, Object... args)
{
log(level, message + " : " + ex.getMessage(), args);
log(level, message, args);
log(level, "Exception : ", ex);
}
static public void info(String message, Object...args)

View File

@ -35,7 +35,6 @@ public class ManageCommand extends Command
@Override
protected void run() throws CommandException
{
//GuiManager.openGui(playerSender(), new MapListGui());
Gui.open(playerSender(), new MapListGui());
}
}

View File

@ -19,8 +19,10 @@
package fr.moribus.imageonmap.guiproko.core;
import org.bukkit.Material;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
@ -30,21 +32,35 @@ abstract public class ExplorerGui<T> extends ActionGui
static protected enum Mode {READONLY, CREATIVE};
private T[] data;
private boolean isData2D = false;
private int viewSize;
private int viewHeight;
private int viewWidth;
private int currentPageX = 0;
private int currentPageY = 0;
private int dataHeight;
private int dataWidth;
private int pageCountX;
private int pageCountY;
private int inventoryViewSize;
private Mode mode = Mode.CREATIVE;
protected void setData(T[] data, int viewWidth)
protected void setData(T[] data, int dataWidth)
{
this.data = data;
this.viewWidth = viewWidth;
if(dataWidth > 0)
setData(dataWidth, (int) Math.ceil((double)data.length / (double)dataWidth));
}
protected void setData(int dataWidth, int dataHeight)
{
this.dataWidth = dataWidth;
this.dataHeight = dataHeight;
this.isData2D = dataWidth > 0;
}
protected void setData(T[] data)
@ -55,10 +71,8 @@ abstract public class ExplorerGui<T> extends ActionGui
@Override
protected void populate(Inventory inventory)
{
int inventorySize = MAX_INVENTORY_SIZE;
if(getPageCount() > 1)
if(pageCountX > 1)
{
inventorySize -= INVENTORY_ROW_SIZE;
if(canGoNext())
updateAction("next", Material.ARROW, "Next page");
else
@ -70,13 +84,42 @@ abstract public class ExplorerGui<T> extends ActionGui
updateAction("previous", Material.STICK, "No previous page");
}
if(viewWidth <= 0)
if(pageCountY > 1)
{
int start = currentPageX * inventorySize;
int max = Math.min(inventorySize, data.length - start);
if(canGoUp())
updateAction("up", Material.ARROW, "Go Up");
else
updateAction("up", Material.STICK, "Top page");
if(canGoDown())
updateAction("down", Material.ARROW, "Go Down");
else
updateAction("down", Material.STICK, "Bottom page");
}
if(!isData2D)
{
int start = currentPageX * viewSize;
int max = Math.min(viewSize, data.length - start);
for(int i = 0; i < max; i++)
{
inventory.setItem(i, getViewItem(data[i + start]));
inventory.setItem(i, getViewItem(i + start));
}
}
else
{
int startX = currentPageX * viewWidth;
int startY = currentPageY * viewHeight;
int maxX = Math.min(viewWidth, dataWidth - startX);
int maxY = Math.min(viewHeight, dataHeight - startY);
for(int i = maxY; i --> 0;)
{
for(int j = maxX; j --> 0;)
{
inventory.setItem(i*INVENTORY_ROW_SIZE + j, getViewItem(j + startX, i + startY));
}
}
}
if(hasActions()) super.populate(inventory);
@ -96,7 +139,14 @@ abstract public class ExplorerGui<T> extends ActionGui
return;
}
if(slot < event.getInventory().getSize())//The user clicked in its own inventory
if(isData2D && pageCountY > 1 &&
slot % INVENTORY_ROW_SIZE == INVENTORY_ROW_SIZE - 1)
{
super.onClick(event);
return;
}
if(affectsGui(event))//The user clicked in its own inventory
{
switch(event.getAction())
{
@ -120,27 +170,53 @@ abstract public class ExplorerGui<T> extends ActionGui
}
}
@Override
protected void onDrag(InventoryDragEvent event)
{
if(!affectsGui(event)) return;
for(int slot : event.getRawSlots())
{
//Clicked in the action bar
if(hasActions() &&
slot >= MAX_INVENTORY_SIZE - INVENTORY_ROW_SIZE
&& slot < MAX_INVENTORY_SIZE)
{
super.onDrag(event);
return;
}
if(isData2D && pageCountY > 1 &&
slot % INVENTORY_ROW_SIZE == INVENTORY_ROW_SIZE - 1)
{
super.onDrag(event);
return;
}
}
event.setCancelled(true);
if(mode.equals(Mode.READONLY)) return;
if(!onPutItem(event.getOldCursor())) return;
event.setCursor(new ItemStack(Material.AIR));
}
private void onActionPickup(InventoryClickEvent event)
{
if(mode.equals(Mode.READONLY))
int dataIndex = getDataIndex(event.getSlot());
if(event.getClick().equals(ClickType.RIGHT))
{
onRightClick(getData(dataIndex));
event.setCancelled(true);
return;
}
int dataIndex = currentPageX * inventoryViewSize + event.getSlot();
if(dataIndex < 0 || dataIndex >= data.length)
{
event.setCancelled(true);
return;
}
ItemStack pickedUpItem = getPickedUpItem(data[dataIndex]);
if(pickedUpItem == null)
ItemStack pickedUpItem = getPickedUpItem(dataIndex);
if(pickedUpItem == null || mode.equals(Mode.READONLY))
{
event.setCancelled(true);
return;
}
event.setCurrentItem(pickedUpItem);
GuiUtils.setItemLater(this, event.getSlot(), getViewItem(data[dataIndex]));
GuiUtils.setItemLater(this, event.getSlot(), getViewItem(dataIndex));
}
private void onActionPut(InventoryClickEvent event)
@ -162,34 +238,56 @@ abstract public class ExplorerGui<T> extends ActionGui
@Override
protected void onAfterUpdate()
{
inventoryViewSize = MAX_INVENTORY_SIZE;
//Calculating page count
if(data.length <= 0)
if(data != null && data.length <= 0)
{
viewWidth = INVENTORY_ROW_SIZE;
viewHeight = 1;
viewSize = viewWidth;
pageCountX = 1;
pageCountY = 1;
}
else if(viewWidth <= 0)
else if(!isData2D)
{
viewWidth = INVENTORY_ROW_SIZE;
viewHeight = Math.min((int)Math.ceil((double)data.length / (double)viewWidth),
MAX_INVENTORY_COLUMN_SIZE);
if(hasActions() || data.length > MAX_INVENTORY_SIZE)
inventoryViewSize -= INVENTORY_ROW_SIZE;
pageCountX = (int)Math.ceil(data.length / inventoryViewSize);
viewHeight--;
viewSize = viewWidth * viewHeight;
pageCountX = (int)Math.ceil((double)data.length / (double)viewSize);
pageCountY = 1;
}
else
{
//TODO: NYI
viewWidth = Math.min(dataWidth, INVENTORY_ROW_SIZE);
viewHeight = Math.min(dataHeight, MAX_INVENTORY_COLUMN_SIZE);
pageCountX = (int)Math.ceil((double)dataWidth / (double)viewWidth);
pageCountY = (int)Math.ceil((double)dataHeight / (double)viewHeight);
if(pageCountY > 1 && viewWidth == INVENTORY_ROW_SIZE) viewWidth--;
if(pageCountX > 1 && viewHeight == MAX_INVENTORY_COLUMN_SIZE) viewHeight--;
pageCountX = (int)Math.ceil((double)dataWidth / (double)viewWidth);
pageCountY = (int)Math.ceil((double)dataHeight / (double)viewHeight);
}
//TODO: Make inventory fit to content
setSize(MAX_INVENTORY_SIZE);
if(pageCountX > 1)
{
action("previous", MAX_INVENTORY_SIZE - INVENTORY_ROW_SIZE);
action("next", MAX_INVENTORY_SIZE - 1);
action("next", MAX_INVENTORY_SIZE - 1 - (pageCountY > 1 ? 1 : 0));
}
if(pageCountY > 1)
{
action("up", INVENTORY_ROW_SIZE - 1);
action("down", MAX_INVENTORY_SIZE - 1);
}
}
@ -203,9 +301,58 @@ abstract public class ExplorerGui<T> extends ActionGui
previous();
}
abstract protected ItemStack getViewItem(T data);
private void action_up()
{
up();
}
private void action_down()
{
down();
}
private int getDataIndex(int inventorySlot)
{
if(isData2D)
{
int column = currentPageX * viewWidth + inventorySlot % INVENTORY_ROW_SIZE;
int row = currentPageY * viewHeight + inventorySlot / INVENTORY_ROW_SIZE;
return row * dataWidth + column;
}
else
{
return currentPageX * viewSize + inventorySlot;
}
}
private T getData(int i)
{
if(i < 0 || i >= data.length)
return null;
return data[i];
}
protected ItemStack getViewItem(int i)
{
return getViewItem(getData(i));
}
protected ItemStack getViewItem(int x, int y)
{
return getViewItem(y * dataWidth + x);
}
protected ItemStack getViewItem(T data){return null;};
private ItemStack getPickedUpItem(int dataIndex)
{
if(dataIndex < 0 || dataIndex >= data.length)
return null;
return getPickedUpItem(getData(dataIndex));
}
protected ItemStack getPickedUpItem(T data){return getViewItem(data);}
protected void onRightClick(T data){}
protected boolean onPutItem(ItemStack item){return true;}
public void next()
@ -222,9 +369,23 @@ abstract public class ExplorerGui<T> extends ActionGui
refresh();
}
public void up()
{
if(!canGoUp()) return;
currentPageY--;
refresh();
}
public void down()
{
if(!canGoDown()) return;
currentPageY++;
refresh();
}
public boolean canGoNext()
{
return currentPageX < pageCountX;
return currentPageX < pageCountX - 1;
}
public boolean canGoPrevious()
@ -232,6 +393,16 @@ abstract public class ExplorerGui<T> extends ActionGui
return currentPageX > 0;
}
public boolean canGoUp()
{
return currentPageY > 0;
}
public boolean canGoDown()
{
return currentPageY < pageCountY - 1;
}
public int getPageCount()
{
return pageCountX;

View File

@ -25,6 +25,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.plugin.Plugin;
@ -147,6 +148,46 @@ abstract public class Gui
*/
abstract protected void onClick(InventoryClickEvent event);
/**
* Raised when an drag is performed on the inventory.
* The default behaviour is to cancel any event that affects the GUI.
* @param event The drag event data.
*/
protected void onDrag(InventoryDragEvent event)
{
if(affectsGui(event)) event.setCancelled(true);
}
/**
* Returns if the given event affects the GUI's inventory
* @param event The event to test
* @return true if the event's slot is in the GUI's inventory,
* false otherwise.
*/
static protected boolean affectsGui(InventoryClickEvent event)
{
return event.getRawSlot() < event.getInventory().getSize();
}
/**
* Returns if the given event affects the GUI's inventory
* @param event The event to test
* @return true if any of the event's slots is in the GUI's inventory,
* false otherwise.
*/
static protected boolean affectsGui(InventoryDragEvent event)
{
for(int slot : event.getRawSlots())
{
if(slot < event.getInventory().getSize())
{
return true;
}
}
return false;
}
/**
* Raised when the GUI is being closed.
* Use this method to cleanup data.
@ -256,6 +297,16 @@ abstract public class Gui
*/
static private class GuiListener implements Listener
{
@EventHandler
public void onInventoryDrag(InventoryDragEvent event)
{
HumanEntity owner = event.getWhoClicked();
Gui openGui = openGuis.get(owner);
if(openGui == null) return;
openGui.onDrag(event);
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event)
{

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2013 Moribus
* Copyright (C) 2015 ProkopyL <prokopylmc@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.moribus.imageonmap.guiproko.list;
import fr.moribus.imageonmap.guiproko.core.ExplorerGui;
import fr.moribus.imageonmap.map.PosterMap;
import fr.moribus.imageonmap.ui.MapItemManager;
import org.bukkit.inventory.ItemStack;
public class MapDetailGui extends ExplorerGui<Void>
{
private final PosterMap map;
public MapDetailGui(PosterMap map)
{
this.map = map;
}
@Override
protected ItemStack getViewItem(int x, int y)
{
return MapItemManager.createSubMapItem(map, x, y);
}
@Override
protected void onUpdate()
{
setTitle("Details for map " + map.getName());
setData(map.getColumnCount(), map.getRowCount());
}
}

View File

@ -19,6 +19,7 @@
package fr.moribus.imageonmap.guiproko.list;
import fr.moribus.imageonmap.guiproko.core.ExplorerGui;
import fr.moribus.imageonmap.guiproko.core.Gui;
import fr.moribus.imageonmap.guiproko.core.GuiUtils;
import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.MapManager;
@ -44,6 +45,13 @@ public class MapListGui extends ExplorerGui<ImageMap>
"Poster map ("+map.getColumnCount()+"x"+map.getRowCount()+")", "#" + data.getId());
}
@Override
protected void onRightClick(ImageMap data)
{
if(data instanceof SingleMap) return;
Gui.open(getPlayer(), new MapDetailGui((PosterMap)data));
}
@Override
protected ItemStack getPickedUpItem(ImageMap map)
{

View File

@ -30,6 +30,12 @@ public class MaterialGui extends ExplorerGui<Material>
{
return new ItemStack(data);
}
@Override
protected void onRightClick(Material data)
{
getPlayer().sendMessage("You clicked : " + data.toString());
}
@Override
protected void onUpdate()

View File

@ -18,6 +18,7 @@
package fr.moribus.imageonmap.ui;
import fr.moribus.imageonmap.guiproko.core.GuiUtils;
import fr.moribus.imageonmap.map.ImageMap;
import fr.moribus.imageonmap.map.PosterMap;
import fr.moribus.imageonmap.map.SingleMap;
@ -120,6 +121,7 @@ public class MapItemManager implements Listener
ItemMeta meta = itemMap.getItemMeta();
meta.setDisplayName(ChatColor.RESET + text);
GuiUtils.hideItemAttributes(meta);
itemMap.setItemMeta(meta);
return itemMap;