diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/Gui.java b/src/main/java/com/github/stefvanschie/inventoryframework/Gui.java index 9d326fe9..7230233e 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/Gui.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/Gui.java @@ -188,6 +188,33 @@ public void show(@NotNull HumanEntity humanEntity) { humanEntity.openInventory(inventory); } + /** + * Makes a copy of this gui and returns it. This makes a deep copy of the gui. This entails that the underlying + * panes will be copied as per their {@link Pane#copy} and miscellaneous data will be copied. The copy of this gui, + * will however have no viewers even if this gui currently has viewers. With this, cache data for viewers will also + * be non-existent for the copied gui. The returned gui will never be reference equal to the current gui. + * + * @return a copy of the gui + * @since 0.6.2 + */ + @NotNull + @Contract(pure = true) + public Gui copy() { + Gui gui = new Gui(getRows(), getTitle()); + + for (Pane pane : panes) { + gui.addPane(pane.copy()); + } + + gui.onTopClick = onTopClick; + gui.onBottomClick = onBottomClick; + gui.onGlobalClick = onGlobalClick; + gui.onOutsideClick = onOutsideClick; + gui.onClose = onClose; + + return gui; + } + /** * Sets the amount of rows for this inventory. * This will (unlike most other methods) directly update itself in order to ensure all viewers will still be viewing the new inventory as well. diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/GuiItem.java b/src/main/java/com/github/stefvanschie/inventoryframework/GuiItem.java index 9cceee36..d46a4f6f 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/GuiItem.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/GuiItem.java @@ -80,6 +80,25 @@ public GuiItem(@NotNull ItemStack item) { this(item, null); } + /** + * Makes a copy of this gui item and returns it. This makes a deep copy of the gui item. This entails that the + * underlying item will be copied as per their {@link ItemStack#clone()} and miscellaneous data will be copied in + * such a way that they are identical with exception to the underlying unique identifier. The returned gui item will + * never be reference equal to the current gui item. + * + * @return a copy of the gui item + * @since 0.6.2 + */ + @NotNull + @Contract(pure = true) + public GuiItem copy() { + GuiItem guiItem = new GuiItem(item.clone(), action); + + guiItem.visible = visible; + + return guiItem; + } + /** * Calls the handler of the {@link InventoryClickEvent} * if such a handler was specified in the constructor. diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/MasonryPane.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/MasonryPane.java index 51613da5..14335de1 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/MasonryPane.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/MasonryPane.java @@ -7,6 +7,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.PlayerInventory; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -188,6 +189,23 @@ public boolean click(@NotNull Gui gui, @NotNull InventoryClickEvent event, int p return success; } + @NotNull + @Contract(pure = true) + @Override + public MasonryPane copy() { + MasonryPane masonryPane = new MasonryPane(x, y, length, height, getPriority()); + + for (Pane pane : panes) { + masonryPane.addPane(pane.copy()); + } + + masonryPane.setVisible(isVisible()); + masonryPane.onClick = onClick; + masonryPane.orientation = orientation; + + return masonryPane; + } + /** * Adds a pane to this masonry pane * diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/OutlinePane.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/OutlinePane.java index 9426c2df..5e43425f 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/OutlinePane.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/OutlinePane.java @@ -246,6 +246,30 @@ public boolean click(@NotNull Gui gui, @NotNull InventoryClickEvent event, int p return true; } + @NotNull + @Contract(pure = true) + @Override + public OutlinePane copy() { + OutlinePane outlinePane = new OutlinePane(x, y, length, height, getPriority()); + + for (GuiItem item : items) { + outlinePane.addItem(item.copy()); + } + + outlinePane.setVisible(isVisible()); + outlinePane.onClick = onClick; + + outlinePane.orientation = orientation; + outlinePane.rotation = rotation; + outlinePane.gap = gap; + outlinePane.repeat = repeat; + outlinePane.flipHorizontally = flipHorizontally; + outlinePane.flipVertically = flipVertically; + outlinePane.mask = mask; + + return outlinePane; + } + @Override public void setRotation(int rotation) { if (length != height) { @@ -375,6 +399,18 @@ public List getItems() { return items; } + /** + * Gets the mask applied to this pane. + * + * @return the mask + * @since 0.6.2 + */ + @NotNull + @Contract(pure = true) + public Mask getMask() { + return mask; + } + /** * Gets the orientation of this outline pane * diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/PaginatedPane.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/PaginatedPane.java index a8f4843f..954b7780 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/PaginatedPane.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/PaginatedPane.java @@ -243,6 +243,26 @@ public boolean click(@NotNull Gui gui, @NotNull InventoryClickEvent event, int p return success; } + @NotNull + @Contract(pure = true) + @Override + public PaginatedPane copy() { + PaginatedPane paginatedPane = new PaginatedPane(x, y, length, height, getPriority()); + + for (Map.Entry> entry : panes.entrySet()) { + for (Pane pane : entry.getValue()) { + paginatedPane.addPane(entry.getKey(), pane.copy()); + } + } + + paginatedPane.setVisible(isVisible()); + paginatedPane.onClick = onClick; + + paginatedPane.page = page; + + return paginatedPane; + } + @NotNull @Contract(pure = true) @Override diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java index baec7678..e50f1596 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java @@ -27,6 +27,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import java.lang.UnsupportedOperationException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; @@ -65,7 +66,7 @@ public abstract class Pane { * The consumer that will be called once a players clicks in this pane */ @Nullable - private Consumer onClick; + protected Consumer onClick; /** * A map containing the mappings for properties for items @@ -119,6 +120,19 @@ protected Pane(int x, int y, int length, int height) { this(x, y, length, height, Priority.NORMAL); } + /** + * Makes a copy of this pane and returns it. This makes a deep copy of the pane. This entails that the underlying + * panes and/or items will be copied as well. The returned pane will never be reference equal to the current pane. + * + * @return a copy of this pane + * @since 0.6.2 + */ + @NotNull + @Contract(pure = true) + public Pane copy() { + throw new UnsupportedOperationException("The implementing pane hasn't overridden the copy method"); + } + /** * Set the length of this pane * diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/StaticPane.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/StaticPane.java index b1e9d6d5..7ec08004 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/StaticPane.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/StaticPane.java @@ -177,7 +177,29 @@ public boolean click(@NotNull Gui gui, @NotNull InventoryClickEvent event, int p return true; } + @NotNull + @Contract(pure = true) @Override + public StaticPane copy() { + StaticPane staticPane = new StaticPane(x, y, length, height, getPriority()); + + for (Map.Entry, GuiItem> entry : items.entrySet()) { + Map.Entry coordinates = entry.getKey(); + + staticPane.addItem(entry.getValue().copy(), coordinates.getKey(), coordinates.getValue()); + } + + staticPane.setVisible(isVisible()); + staticPane.onClick = onClick; + + staticPane.rotation = rotation; + staticPane.flipHorizontally = flipHorizontally; + staticPane.flipVertically = flipVertically; + + return staticPane; + } + + @Override public void setRotation(int rotation) { if (length != height) { throw new UnsupportedOperationException("length and height are different"); diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java index d92c6264..0dc20ebf 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java @@ -8,6 +8,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.PlayerInventory; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -101,6 +102,24 @@ public void display(@NotNull Gui gui, @NotNull Inventory inventory, @NotNull Pla panes.get(position).display(gui, inventory, playerInventory, newX, newY, newMaxLength, newMaxHeight); } + @NotNull + @Contract(pure = true) + @Override + public CycleButton copy() { + CycleButton cycleButton = new CycleButton(x, y, length, height, getPriority()); + + for (Pane pane : panes) { + cycleButton.addPane(pane); + } + + cycleButton.setVisible(isVisible()); + cycleButton.onClick = onClick; + + cycleButton.position = position; + + return cycleButton; + } + @NotNull @Override public Collection getItems() { diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Label.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Label.java index 6edebe95..f77bb62d 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Label.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Label.java @@ -109,6 +109,32 @@ public void setText(@NotNull String text) { } } + @NotNull + @Contract(pure = true) + @Override + public Label copy() { + Label label = new Label(x, y, length, height, getPriority(), font); + + for (GuiItem item : getItems()) { + label.addItem(item.copy()); + } + + label.setVisible(isVisible()); + label.onClick = onClick; + + label.setOrientation(getOrientation()); + label.setRotation(getRotation()); + label.setGap(getGap()); + label.setRepeat(doesRepeat()); + label.flipHorizontally(isFlippedHorizontally()); + label.flipVertically(isFlippedVertically()); + label.applyMask(getMask()); + + label.text = text; + + return label; + } + @Override public boolean click(@NotNull Gui gui, @NotNull InventoryClickEvent event, int paneOffsetX, int paneOffsetY, int maxLength, int maxHeight) { diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/PercentageBar.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/PercentageBar.java index 7b69b952..023f3b70 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/PercentageBar.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/PercentageBar.java @@ -103,6 +103,17 @@ public void setPercentage(float percentage) { } } + @NotNull + @Contract(pure = true) + @Override + public PercentageBar copy() { + PercentageBar percentageBar = new PercentageBar(x, y, length, height, getPriority()); + + applyContents(percentageBar); + + return percentageBar; + } + /** * Gets the percentage as a float in between (0,1) this bar is currently set at. * diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Slider.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Slider.java index 3799a826..a503a4e7 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Slider.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/Slider.java @@ -113,6 +113,17 @@ public void setValue(float value) { } } + @NotNull + @Contract(pure = true) + @Override + public Slider copy() { + Slider slider = new Slider(x, y, length, height, getPriority()); + + applyContents(slider); + + return slider; + } + /** * Gets the value as a float in between (0,1) this bar is currently set at. * diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/ToggleButton.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/ToggleButton.java index d503736b..42fb5043 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/ToggleButton.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/ToggleButton.java @@ -124,6 +124,23 @@ public boolean click(@NotNull Gui gui, @NotNull InventoryClickEvent event, int p return true; } + @NotNull + @Contract(pure = true) + @Override + public ToggleButton copy() { + ToggleButton toggleButton = new ToggleButton(x, y, length, height, getPriority()); + + toggleButton.setVisible(isVisible()); + toggleButton.onClick = onClick; + + toggleButton.setEnabledItem(enabledPane.getItems().get(0).copy()); + toggleButton.setDisabledItem(disabledPane.getItems().get(0).copy()); + + toggleButton.enabled = enabled; + + return toggleButton; + } + /** * Sets the item to use when the button is set to disabled * diff --git a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/util/VariableBar.java b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/util/VariableBar.java index fbfadadb..3b343084 100644 --- a/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/util/VariableBar.java +++ b/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/util/VariableBar.java @@ -114,6 +114,33 @@ public void setHeight(int height) { this.backgroundPane.setHeight(height); } + /** + * Applies the contents of this variable bar onto the provided copy of this variable bar. This variable bar will not + * be modified. + * + * @param copy the copy of the variable bar + * @since 0.6.2 + */ + protected void applyContents(@NotNull VariableBar copy) { + copy.x = x; + copy.y = y; + copy.length = length; + copy.height = height; + copy.setPriority(getPriority()); + + copy.setVisible(isVisible()); + copy.onClick = onClick; + + copy.setFillItem(fillPane.getItems().get(0).copy()); + copy.setBackgroundItem(backgroundPane.getItems().get(0).copy()); + + copy.value = value; + copy.orientation = orientation; + + copy.flipHorizontally = flipHorizontally; + copy.flipVertically = flipVertically; + } + @Override public void setOrientation(@NotNull Orientation orientation) { this.orientation = orientation; diff --git a/src/test/java/com/github/stefvanschie/inventoryframework/pane/MasonryPaneTest.java b/src/test/java/com/github/stefvanschie/inventoryframework/pane/MasonryPaneTest.java new file mode 100644 index 00000000..aa973175 --- /dev/null +++ b/src/test/java/com/github/stefvanschie/inventoryframework/pane/MasonryPaneTest.java @@ -0,0 +1,36 @@ +package com.github.stefvanschie.inventoryframework.pane; + +import com.github.stefvanschie.inventoryframework.pane.component.CycleButton; +import com.github.stefvanschie.inventoryframework.pane.component.ToggleButton; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class MasonryPaneTest { + + @Test + void testCopy() { + MasonryPane original = new MasonryPane(7, 5, 1, 1, Pane.Priority.LOW); + original.setVisible(false); + original.setOrientation(Orientable.Orientation.VERTICAL); + + original.addPane(new CycleButton(1, 1)); + original.addPane(new StaticPane(1, 1)); + original.addPane(new PaginatedPane(1, 1)); + original.addPane(new MasonryPane(1, 1)); + original.addPane(new OutlinePane(1, 1)); + + MasonryPane copy = original.copy(); + + assertNotSame(original, copy); + + assertEquals(original.getX(), copy.getX()); + assertEquals(original.getY(), copy.getY()); + assertEquals(original.getLength(), copy.getLength()); + assertEquals(original.getHeight(), copy.getHeight()); + assertEquals(original.getPriority(), copy.getPriority()); + assertEquals(original.isVisible(), copy.isVisible()); + assertEquals(original.getOrientation(), copy.getOrientation()); + assertEquals(original.getPanes().size(), copy.getPanes().size()); + } +} diff --git a/src/test/java/com/github/stefvanschie/inventoryframework/pane/OutlinePaneTest.java b/src/test/java/com/github/stefvanschie/inventoryframework/pane/OutlinePaneTest.java index c1df6e9d..f16c4220 100644 --- a/src/test/java/com/github/stefvanschie/inventoryframework/pane/OutlinePaneTest.java +++ b/src/test/java/com/github/stefvanschie/inventoryframework/pane/OutlinePaneTest.java @@ -12,4 +12,35 @@ void testApplyMaskInvalidDimensions() { assertThrows(IllegalArgumentException.class, () -> new OutlinePane(3, 7).applyMask(new Mask("0", "1"))); } + + @Test + void testCopy() { + OutlinePane original = new OutlinePane(8, 5, 1, 1, Pane.Priority.HIGHEST); + original.setVisible(false); + original.setOrientation(Orientable.Orientation.VERTICAL); + original.setRotation(180); + original.setGap(0); + original.setRepeat(false); + original.flipHorizontally(true); + original.flipVertically(true); + original.applyMask(new Mask("0")); + + OutlinePane copy = original.copy(); + + assertNotSame(original, copy); + + assertEquals(original.getX(), copy.getX()); + assertEquals(original.getY(), copy.getY()); + assertEquals(original.getLength(), copy.getLength()); + assertEquals(original.getHeight(), copy.getHeight()); + assertEquals(original.getPriority(), copy.getPriority()); + assertEquals(original.isVisible(), copy.isVisible()); + assertEquals(original.getOrientation(), copy.getOrientation()); + assertEquals(original.getRotation(), copy.getRotation()); + assertEquals(original.getGap(), copy.getGap()); + assertEquals(original.doesRepeat(), copy.doesRepeat()); + assertEquals(original.isFlippedHorizontally(), copy.isFlippedHorizontally()); + assertEquals(original.isFlippedVertically(), copy.isFlippedVertically()); + assertEquals(original.getMask(), copy.getMask()); + } } diff --git a/src/test/java/com/github/stefvanschie/inventoryframework/pane/PaginatedPaneTest.java b/src/test/java/com/github/stefvanschie/inventoryframework/pane/PaginatedPaneTest.java new file mode 100644 index 00000000..5c120246 --- /dev/null +++ b/src/test/java/com/github/stefvanschie/inventoryframework/pane/PaginatedPaneTest.java @@ -0,0 +1,39 @@ +package com.github.stefvanschie.inventoryframework.pane; + +import com.github.stefvanschie.inventoryframework.font.util.Font; +import com.github.stefvanschie.inventoryframework.pane.component.Label; +import com.github.stefvanschie.inventoryframework.pane.component.PercentageBar; +import com.github.stefvanschie.inventoryframework.pane.component.ToggleButton; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class PaginatedPaneTest { + + @Test + void testCopy() { + PaginatedPane original = new PaginatedPane(5, 5, 4, 1, Pane.Priority.NORMAL); + original.setVisible(false); + + original.addPane(0, new OutlinePane(1, 1)); + original.addPane(1, new OutlinePane(1, 1)); + original.addPane(2, new PaginatedPane(1, 1)); + original.addPane(3, new PaginatedPane(1, 1)); + original.addPane(4, new OutlinePane(1, 1)); + + original.setPage(4); + + PaginatedPane copy = original.copy(); + + assertNotSame(original, copy); + + assertEquals(original.getX(), copy.getX()); + assertEquals(original.getY(), copy.getY()); + assertEquals(original.getLength(), copy.getLength()); + assertEquals(original.getHeight(), copy.getHeight()); + assertEquals(original.getPriority(), copy.getPriority()); + assertEquals(original.isVisible(), copy.isVisible()); + assertEquals(original.getPage(), copy.getPage()); + assertEquals(original.getPages(), copy.getPages()); + } +} diff --git a/src/test/java/com/github/stefvanschie/inventoryframework/pane/StaticPaneTest.java b/src/test/java/com/github/stefvanschie/inventoryframework/pane/StaticPaneTest.java new file mode 100644 index 00000000..31c4f5c7 --- /dev/null +++ b/src/test/java/com/github/stefvanschie/inventoryframework/pane/StaticPaneTest.java @@ -0,0 +1,31 @@ +package com.github.stefvanschie.inventoryframework.pane; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class StaticPaneTest { + + @Test + void testCopy() { + StaticPane original = new StaticPane(5, 1, 1, 1, Pane.Priority.MONITOR); + original.setVisible(false); + original.setRotation(90); + original.flipHorizontally(false); + original.flipVertically(true); + + StaticPane copy = original.copy(); + + assertNotSame(original, copy); + + assertEquals(original.getX(), copy.getX()); + assertEquals(original.getY(), copy.getY()); + assertEquals(original.getLength(), copy.getLength()); + assertEquals(original.getHeight(), copy.getHeight()); + assertEquals(original.getPriority(), copy.getPriority()); + assertEquals(original.isVisible(), copy.isVisible()); + assertEquals(original.getRotation(), copy.getRotation()); + assertEquals(original.isFlippedHorizontally(), copy.isFlippedHorizontally()); + assertEquals(original.isFlippedVertically(), copy.isFlippedVertically()); + } +} diff --git a/src/test/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButtonTest.java b/src/test/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButtonTest.java new file mode 100644 index 00000000..80108020 --- /dev/null +++ b/src/test/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButtonTest.java @@ -0,0 +1,29 @@ +package com.github.stefvanschie.inventoryframework.pane.component; + +import com.github.stefvanschie.inventoryframework.pane.Pane; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class CycleButtonTest { + + @Test + void testCopy() { + CycleButton original = new CycleButton(6, 2, 2, 3, Pane.Priority.HIGH); + original.setVisible(true); + + original.addPane(new CycleButton(1, 1)); + + CycleButton copy = original.copy(); + + assertNotSame(original, copy); + + assertEquals(original.getX(), copy.getX()); + assertEquals(original.getY(), copy.getY()); + assertEquals(original.getLength(), copy.getLength()); + assertEquals(original.getHeight(), copy.getHeight()); + assertEquals(original.getPriority(), copy.getPriority()); + assertEquals(original.isVisible(), copy.isVisible()); + assertEquals(original.getPanes().size(), copy.getPanes().size()); + } +}