From 7809c95d80d0da61ecdeb4e9e5958b11ffd44c43 Mon Sep 17 00:00:00 2001 From: Amaury Carrade Date: Sun, 12 Jul 2015 16:04:19 +0200 Subject: [PATCH] Added a map details GUI. * NEW: Right-clicking on a GUI opens another one with details about the map. * NEW: The details GUI displays the map on a screen with scrollbars to consult the map per-minecraft-map. * NEW: Each part of the map can be taken independently. --- .../imageonmap/gui/list/MapDetailGui.java | 318 ++++++++++++++++++ .../imageonmap/gui/list/MapListGui.java | 2 +- .../fr/moribus/imageonmap/map/PosterMap.java | 17 +- .../moribus/imageonmap/ui/MapItemManager.java | 46 ++- 4 files changed, 375 insertions(+), 8 deletions(-) create mode 100644 src/main/java/fr/moribus/imageonmap/gui/list/MapDetailGui.java diff --git a/src/main/java/fr/moribus/imageonmap/gui/list/MapDetailGui.java b/src/main/java/fr/moribus/imageonmap/gui/list/MapDetailGui.java new file mode 100644 index 0000000..2ab4e85 --- /dev/null +++ b/src/main/java/fr/moribus/imageonmap/gui/list/MapDetailGui.java @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2013 Moribus + * Copyright (C) 2015 ProkopyL + * + * 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 . + */ + +package fr.moribus.imageonmap.gui.list; + +import fr.moribus.imageonmap.gui.core.AbstractGui; +import fr.moribus.imageonmap.gui.core.GuiManager; +import fr.moribus.imageonmap.map.ImageMap; +import fr.moribus.imageonmap.map.PosterMap; +import fr.moribus.imageonmap.ui.MapItemManager; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.Arrays; +import java.util.Collections; + + +public class MapDetailGui extends AbstractGui +{ + + /** + * The max width of the window open on the image. + */ + private final int MAX_WINDOW_WIDTH = 7; + + /** + * The max height of the window open on the image. + */ + private final int MAX_WINDOW_HEIGHT = 3; + + + + /** + * The map displayed in this GUI. + */ + ImageMap map; + + /** + * The previously-viewed page of the list GUI. + * Used to be able to bring the user back to the same page. + */ + int currentPage; + + /** + * The row currently at the top of the window open on the displayed map. + */ + int topRow = 0; + + /** + * The column currently at the top of the window open on the displayed map. + */ + int topColumn = 0; + + + /** + * + * @param map The map displayed in this GUI. + */ + public MapDetailGui(ImageMap map) + { + this(map, 0); + } + + /** + * + * @param map The map displayed in this GUI. + * @param currentPage The previously-viewed page of the list GUI. + */ + public MapDetailGui(ImageMap map, int currentPage) + { + this.map = map; + this.currentPage = currentPage; + } + + + @Override + public void display(Player player) + { + inventory = Bukkit.createInventory(player, 6 * 9, ChatColor.BLACK + "Your maps"); + + ItemStack back = new ItemStack(Material.EMERALD); + ItemMeta meta = back.getItemMeta(); + meta.setDisplayName(ChatColor.GREEN + "« Back"); + meta.setLore(Collections.singletonList( + ChatColor.GRAY + "Go back to the list." + )); + back.setItemMeta(meta); + + setSlotData(back, inventory.getSize() - 5, "back"); + + update(player); + + player.openInventory(inventory); + } + + @Override + public void update(Player player) + { + /* ** The map itself ** */ + + if(map instanceof PosterMap && ((PosterMap) map).hasColumnData()) { + int slot = 10; + + for (int row = topRow; row < topRow + MAX_WINDOW_HEIGHT; row++) + { + for (int col = topColumn; col < topColumn + MAX_WINDOW_WIDTH; col++) + { + if(col < ((PosterMap) map).getColumnCount() && row < ((PosterMap) map).getRowCount()) + { + setSlotData(getMapPartRepresentation(col, row), slot, col + ";" + row); + } + else + { + setSlotData(new ItemStack(Material.AIR), slot, ""); + } + + slot++; + } + + slot += 2; + } + + placeArrowSlider('\u2B07', canGoDown(), 35, "down"); + placeArrowSlider('\u2B06', canGoUp() , 17, "up" ); + placeArrowSlider('«' , canGoLeft() , 37, "left" ); + placeArrowSlider('»' , canGoRight(), 43, "right"); + } + + else + { + setSlotData(getMapPartRepresentation(0, 0), 13, "0;0"); + } + } + + private ItemStack getMapPartRepresentation(int col, int row) + { + ItemStack part = new ItemStack(Material.MAP); + ItemMeta meta = part.getItemMeta(); + + meta.setDisplayName(ChatColor.GREEN + "Map part"); + meta.setLore(Arrays.asList( + ChatColor.GRAY + "Column: " + ChatColor.WHITE + (col + 1), + ChatColor.GRAY + "Row: " + ChatColor.WHITE + (row + 1), + "", + ChatColor.GRAY + "» Click to get only this part" + )); + + part.setItemMeta(meta); + return part; + } + + private void placeArrowSlider(Character nameCharacter, boolean active, int slot, String action) + { + /* ** Item ** */ + + ItemStack slider = new ItemStack(Material.ARROW); + ItemMeta meta = slider.getItemMeta(); + + String title = ""; + for(int i = 0; i < 5; i++) + title += nameCharacter; + + meta.setDisplayName((active ? ChatColor.GREEN : ChatColor.GRAY) + title); + + slider.setItemMeta(meta); + + + /* ** Placement ** */ + + setSlotData(slider, slot, active ? action : ""); + } + + + @Override + public void onClick(Player player, ItemStack stack, String action, ClickType click, InventoryAction invAction, InventoryClickEvent ev) + { + switch (action) + { + case "down": + goDown(player); + return; + + case "up": + goUp(player); + return; + + case "left": + goLeft(player); + return; + + case "right": + goRight(player); + return; + + case "back": + goBack(player); + return; + + default: + + Integer col; + Integer row; + + if(map instanceof PosterMap && ((PosterMap) map).hasColumnData()) { + String[] coords = action.split(";"); + + if (coords.length != 2) return; // Other unhandled action. + + try { + col = Integer.valueOf(coords[0]); + row = Integer.valueOf(coords[1]); + + } catch (NumberFormatException e) { + return; // Other unhandled action. + } + } + else + { + col = row = 0; + } + + ev.setCursor(MapItemManager.createSubMapItem(map, col, row)); + } + } + + + private void goDown(Player player) + { + if (!(map instanceof PosterMap)) return; + + if(canGoDown()) + { + topRow++; + update(player); + } + } + + private void goUp(Player player) + { + if (!(map instanceof PosterMap)) return; + + if(canGoUp()) + { + topRow--; + update(player); + } + } + + private void goRight(Player player) + { + if (!(map instanceof PosterMap)) return; + + if(canGoRight()) + { + topColumn++; + update(player); + } + } + + private void goLeft(Player player) + { + if (!(map instanceof PosterMap)) return; + + if(canGoLeft()) + { + topColumn--; + update(player); + } + } + + private void goBack(Player player) + { + GuiManager.openGui(player, new MapListGui(currentPage)); + } + + + private boolean canGoDown() + { + return topRow + MAX_WINDOW_HEIGHT < ((PosterMap) map).getRowCount(); + } + + private boolean canGoUp() + { + return topRow > 0; + } + + private boolean canGoRight() + { + return topColumn + MAX_WINDOW_WIDTH < ((PosterMap) map).getColumnCount(); + } + + private boolean canGoLeft() + { + return topColumn > 0; + } +} diff --git a/src/main/java/fr/moribus/imageonmap/gui/list/MapListGui.java b/src/main/java/fr/moribus/imageonmap/gui/list/MapListGui.java index f24ee39..8a2d9a7 100644 --- a/src/main/java/fr/moribus/imageonmap/gui/list/MapListGui.java +++ b/src/main/java/fr/moribus/imageonmap/gui/list/MapListGui.java @@ -173,7 +173,7 @@ public class MapListGui extends AbstractGui case RIGHT: case SHIFT_RIGHT: - // TODO + GuiManager.openGui(player, new MapDetailGui(map, currentPage)); break; } } diff --git a/src/main/java/fr/moribus/imageonmap/map/PosterMap.java b/src/main/java/fr/moribus/imageonmap/map/PosterMap.java index 0139cdc..ba0bf93 100644 --- a/src/main/java/fr/moribus/imageonmap/map/PosterMap.java +++ b/src/main/java/fr/moribus/imageonmap/map/PosterMap.java @@ -18,10 +18,11 @@ package fr.moribus.imageonmap.map; +import org.bukkit.configuration.InvalidConfigurationException; + import java.util.List; import java.util.Map; import java.util.UUID; -import org.bukkit.configuration.InvalidConfigurationException; public class PosterMap extends ImageMap { @@ -115,6 +116,20 @@ public class PosterMap extends ImageMap if(columnCount == 0) return 0; return (i / columnCount) + 1; } + + /** + * Returns the map id at the given column and line. + * + * @param col The column. Starts at 0. + * @param row The row. Starts at 0. + * @return The Minecraft map ID. + * + * @throws ArrayIndexOutOfBoundsException if the given coordinates are too big (out of the poster). + */ + public short getMapIdAt(int col, int row) + { + return mapsIDs[getColumnCount() * col + row]; + } public boolean hasColumnData() { diff --git a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java index 9559ef4..bdd6328 100644 --- a/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java +++ b/src/main/java/fr/moribus/imageonmap/ui/MapItemManager.java @@ -21,10 +21,7 @@ package fr.moribus.imageonmap.ui; import fr.moribus.imageonmap.map.ImageMap; import fr.moribus.imageonmap.map.PosterMap; import fr.moribus.imageonmap.map.SingleMap; -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.Queue; -import java.util.UUID; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.Listener; @@ -32,6 +29,11 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.Queue; +import java.util.UUID; + public class MapItemManager implements Listener { static private HashMap> mapItemCache; @@ -69,7 +71,7 @@ public class MapItemManager implements Listener { if(map.hasColumnData()) { - mapName = map.getName() + + mapName = map.getName() + " (row " + map.getRowAt(i) + ", column " + map.getColumnAt(i) + ")"; } @@ -117,11 +119,43 @@ public class MapItemManager implements Listener ItemStack itemMap = new ItemStack(Material.MAP, 1, mapID); ItemMeta meta = itemMap.getItemMeta(); - meta.setDisplayName(text); + meta.setDisplayName(ChatColor.RESET + text); itemMap.setItemMeta(meta); return itemMap; } + + /** + * Returns the item to place to display the (col;row) part of the given poster. + * + * @param col The column to display. Starts at 0. + * @param row The row to display. Starts at 0. + * + * @return The map. + * + * @throws ArrayIndexOutOfBoundsException If col;row is not inside the map. + */ + static public ItemStack createSubMapItem(ImageMap map, int col, int row) + { + if(map instanceof PosterMap && ((PosterMap) map).hasColumnData()) + { + return MapItemManager.createMapItem( + ((PosterMap) map).getMapIdAt(row, col), + map.getName() + + " (row " + (row + 1) + + ", column " + (col + 1) + ")" + ); + } + else + { + if(row != 0 || col != 0) + { + throw new ArrayIndexOutOfBoundsException(); // Coherence + } + + return MapItemManager.createMapItem(map.getMapsIDs()[0], map.getName()); + } + } static public int getCacheSize(Player player) {