diff --git a/api/src/main/kotlin/com/mattmx/ktgui/components/button/GuiButton.kt b/api/src/main/kotlin/com/mattmx/ktgui/components/button/GuiButton.kt index ea19e21..0246742 100644 --- a/api/src/main/kotlin/com/mattmx/ktgui/components/button/GuiButton.kt +++ b/api/src/main/kotlin/com/mattmx/ktgui/components/button/GuiButton.kt @@ -86,6 +86,17 @@ open class GuiButton>( return this as T } + fun removeSlots(vararg slot: Int) : T = apply { + if (hasParent()) { + slots?.removeAll(slot.toSet()) + parent.clearSlot(*slot) + } else { + if (slots != null) { + slots?.removeAll(slot.toSet()) + } + } + } as T + override infix fun slot(slot: Int): T { if (hasParent()) { if (slots == null) slots = arrayListOf() diff --git a/api/src/main/kotlin/com/mattmx/ktgui/components/screen/GuiScreen.kt b/api/src/main/kotlin/com/mattmx/ktgui/components/screen/GuiScreen.kt index 516e0c3..c7b3cea 100644 --- a/api/src/main/kotlin/com/mattmx/ktgui/components/screen/GuiScreen.kt +++ b/api/src/main/kotlin/com/mattmx/ktgui/components/screen/GuiScreen.kt @@ -88,6 +88,12 @@ open class GuiScreen( return this } + override fun clearSlot(vararg slot: Int) { + for (s in slot) { + items.remove(s) + } + } + fun slotsUsed(): List = items.map { it.key } fun findButton(id: String) = findButtons(id).firstOrNull() diff --git a/api/src/main/kotlin/com/mattmx/ktgui/components/screen/IGuiScreen.kt b/api/src/main/kotlin/com/mattmx/ktgui/components/screen/IGuiScreen.kt index 4d0d5f1..14555b9 100644 --- a/api/src/main/kotlin/com/mattmx/ktgui/components/screen/IGuiScreen.kt +++ b/api/src/main/kotlin/com/mattmx/ktgui/components/screen/IGuiScreen.kt @@ -18,6 +18,8 @@ interface IGuiScreen { fun setSlot(button: IGuiButton<*>, slot: Int) : IGuiScreen + fun clearSlot(vararg slot: Int) + fun open(player: Player) fun copy() : IGuiScreen diff --git a/plugin/src/main/kotlin/com/mattmx/ktgui/KotlinGui.kt b/plugin/src/main/kotlin/com/mattmx/ktgui/KotlinGui.kt index 730d1d5..170dc7b 100644 --- a/plugin/src/main/kotlin/com/mattmx/ktgui/KotlinGui.kt +++ b/plugin/src/main/kotlin/com/mattmx/ktgui/KotlinGui.kt @@ -2,6 +2,7 @@ package com.mattmx.ktgui import com.mattmx.ktgui.commands.rawCommand import com.mattmx.ktgui.commands.simpleCommand +import com.mattmx.ktgui.creator.GuiDesigner import com.mattmx.ktgui.examples.* import com.mattmx.ktgui.utils.not import com.mattmx.ktgui.utils.pretty @@ -98,6 +99,44 @@ class KotlinGui : JavaPlugin() { player.sendMessage(!"&cPlease wait before doing that again.") } } + + val cachedDesigners = hashMapOf() + subCommands += rawCommand("designer") { + permission = "ktgui.command.designer" + playerOnly = true + suggestSubCommands = true + + subCommands += rawCommand("open") { + permission = "ktgui.command.designer" + playerOnly = true + + runs { + val id = args.getOrNull(2) + ?: return@runs source.sendMessage(!"&cProvide an id of the designer") + + val designer = cachedDesigners.getOrPut(id) { GuiDesigner(id) } + designer.open(player) + } + + suggestion { cachedDesigners.keys.filter { it.startsWith(lastArg, true) } } + } + + subCommands += rawCommand("export") { + permission = "ktgui.command.designer" + playerOnly = true + + runs { + val id = args.getOrNull(2) + ?: return@runs source.sendMessage(!"&cProvide an id of the designer") + + val designer = cachedDesigners.getOrPut(id) { GuiDesigner(id) } + val file = designer.save(this@KotlinGui) + source.sendMessage(!"&aSaved to /plugins/KtGUI/designer/${file.name}") + } + + suggestion { cachedDesigners.keys.filter { it.startsWith(lastArg, true) } } + } + } }.register(false) } diff --git a/plugin/src/main/kotlin/com/mattmx/ktgui/creator/GuiDesigner.kt b/plugin/src/main/kotlin/com/mattmx/ktgui/creator/GuiDesigner.kt index a273de8..e57b5fc 100644 --- a/plugin/src/main/kotlin/com/mattmx/ktgui/creator/GuiDesigner.kt +++ b/plugin/src/main/kotlin/com/mattmx/ktgui/creator/GuiDesigner.kt @@ -1,18 +1,47 @@ package com.mattmx.ktgui.creator +import com.mattmx.ktgui.KotlinGui +import com.mattmx.ktgui.components.button.GuiButton import com.mattmx.ktgui.components.screen.GuiScreen +import com.mattmx.ktgui.dsl.button import com.mattmx.ktgui.utils.not +import java.io.File class GuiDesigner( val name: String ) : GuiScreen(!"Designer ($name&r)") { init { - click.any { + click.left { event.isCancelled = false - // todo save instance + if (slot !in 0..last()) { + return@left + } + + val existing = items[slot] + items.remove(slot) + existing?.removeSlots(slot) + + GuiButton(item = itemClicked) childOf this@GuiDesigner slot slot + } + + click.right { + if (isButton()) { + GuiDesignerButtonCustomizer(this@GuiDesigner, button as GuiButton<*>).open(player) + } + } + } + + fun save(plugin: KotlinGui): File { + val file = File("${plugin.dataFolder}/designer/$name.kt") + + if (file.exists()) { + file.parentFile.mkdirs() + file.createNewFile() } + file.writeText(export()) + return file } fun export(): String { diff --git a/plugin/src/main/kotlin/com/mattmx/ktgui/creator/GuiDesignerButtonCustomizer.kt b/plugin/src/main/kotlin/com/mattmx/ktgui/creator/GuiDesignerButtonCustomizer.kt new file mode 100644 index 0000000..43facb1 --- /dev/null +++ b/plugin/src/main/kotlin/com/mattmx/ktgui/creator/GuiDesignerButtonCustomizer.kt @@ -0,0 +1,108 @@ +package com.mattmx.ktgui.creator + +import com.mattmx.ktgui.components.button.GuiButton +import com.mattmx.ktgui.components.screen.GuiScreen +import com.mattmx.ktgui.conversation.refactor.conversation +import com.mattmx.ktgui.conversation.refactor.getString +import com.mattmx.ktgui.dsl.button +import com.mattmx.ktgui.extensions.getOpenGui +import com.mattmx.ktgui.scheduling.sync +import com.mattmx.ktgui.utils.legacy +import com.mattmx.ktgui.utils.not +import net.kyori.adventure.text.format.TextColor +import org.bukkit.Material +import org.bukkit.entity.Player + +class GuiDesignerButtonCustomizer( + val parent: GuiDesigner, + val button: GuiButton<*> +) : GuiScreen(!"Customize Button", 3) { + + init { + button(Material.SPECTRAL_ARROW) { + named(!"&dBack") + leftClick { + openParent(player) + } + } slot 22 + + button(Material.NAME_TAG) { + named(!"&dName") + lore { + add(!"&fCurrently: ${button.item?.displayName()?.legacy()}") + } + leftClick { + conversation { + getString { + message = !"&dInput a new item name" + + runs { + result.ifPresent { result -> + button.named(!result) + } + open(player) + } + } + exitOn = "cancel" + exit { + open(player) + } + } begin player + } + } slot 10 + + button(Material.MOJANG_BANNER_PATTERN) { + named(!"&dLore") + lore { + val isEmpty = button.item?.lore()?.isEmpty() ?: true + add(!"&fCurrently: ${if (isEmpty) "&7*None*" else ""}") + + button.item?.lore()?.forEach { line -> add(line) } + } + leftClick { + conversation { + getString { + matches { result.isPresent && result.get().equals("cancel", true) } + invalid { + result.ifPresent { + button.lore(!it) + } + player.sendMessage(!"&fType 'cancel' to stop.") + player.sendMessage(!"&fCurrently:") + button.item?.lore()?.forEach { line -> player.sendMessage(line) } + } + runs { + open(player) + } + } + } begin player + } + } slot 13 + + button(Material.ENCHANTED_BOOK) { + named(!"&dEnchantments") + lore { + val isEmpty = button.item?.enchantments?.isEmpty() ?: true + add(!"&fCurrently: ${if (isEmpty) "&7*None*" else ""}") + + button.item?.enchantments?.forEach { line -> + line.key.displayName(line.value).color(TextColor.color(0xFFFFFF)) + } + } + } slot 16 + + close { + val player = it.player as Player + openParent(player) + } + } + + fun openParent(player: Player) { + sync { + if (player.getOpenGui() == this@GuiDesignerButtonCustomizer) { + parent.open(player) + } + } + } + +} \ No newline at end of file