From 6045077025629cabc1831a281fec532faa7781dd Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Sun, 17 Nov 2024 18:33:29 +0100 Subject: fix: Fix position of inventory buttons during preset importing --- .../inventory/buttons/InventoryButtonEditor.kt | 355 +++++++++++---------- .../inventory/buttons/InventoryButtonTemplates.kt | 42 ++- 2 files changed, 215 insertions(+), 182 deletions(-) (limited to 'src/main/kotlin/features') diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt b/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt index 7bf9c73..ee3ae8b 100644 --- a/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt +++ b/src/main/kotlin/features/inventory/buttons/InventoryButtonEditor.kt @@ -1,5 +1,3 @@ - - package moe.nea.firmament.features.inventory.buttons import io.github.notenoughupdates.moulconfig.common.IItemStack @@ -18,166 +16,203 @@ import moe.nea.firmament.util.ClipboardUtils import moe.nea.firmament.util.FragmentGuiScreen import moe.nea.firmament.util.MC import moe.nea.firmament.util.MoulConfigUtils +import moe.nea.firmament.util.tr class InventoryButtonEditor( - val lastGuiRect: Rectangle, + val lastGuiRect: Rectangle, ) : FragmentGuiScreen() { - inner class Editor(val originalButton: InventoryButton) { - @field:Bind - var command: String = originalButton.command ?: "" - - @field:Bind - var icon: String = originalButton.icon ?: "" - - @Bind - fun getItemIcon(): IItemStack { - save() - return ModernItemStack.of(InventoryButton.getItemForName(icon)) - } - - @Bind - fun delete() { - buttons.removeIf { it === originalButton } - popup = null - } - - fun save() { - originalButton.icon = icon - originalButton.command = command - } - } - - var buttons: MutableList = - InventoryButtons.DConfig.data.buttons.map { it.copy() }.toMutableList() - - override fun close() { - InventoryButtons.DConfig.data.buttons = buttons - InventoryButtons.DConfig.markDirty() - super.close() - } - - override fun init() { - super.init() - addDrawableChild( - ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.load-preset")) { - val t = ClipboardUtils.getTextContents() - val newButtons = InventoryButtonTemplates.loadTemplate(t) - if (newButtons != null) - buttons = newButtons.toMutableList() - } - .position(lastGuiRect.minX + 10, lastGuiRect.minY + 35) - .width(lastGuiRect.width - 20) - .build() - ) - addDrawableChild( - ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.save-preset")) { - ClipboardUtils.setTextContent(InventoryButtonTemplates.saveTemplate(buttons)) - } - .position(lastGuiRect.minX + 10, lastGuiRect.minY + 60) - .width(lastGuiRect.width - 20) - .build() - ) - } - - override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { - super.render(context, mouseX, mouseY, delta) - context.matrices.push() - context.matrices.translate(0f, 0f, -10f) - context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1) - context.matrices.pop() - for (button in buttons) { - val buttonPosition = button.getBounds(lastGuiRect) - context.matrices.push() - context.matrices.translate(buttonPosition.minX.toFloat(), buttonPosition.minY.toFloat(), 0F) - button.render(context) - context.matrices.pop() - } - } - - override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { - if (super.keyPressed(keyCode, scanCode, modifiers)) return true - if (keyCode == GLFW.GLFW_KEY_ESCAPE) { - close() - return true - } - return false - } - - override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { - if (super.mouseReleased(mouseX, mouseY, button)) return true - val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) } - if (clickedButton != null && !justPerformedAClickAction) { - createPopup(MoulConfigUtils.loadGui("button_editor_fragment", Editor(clickedButton)), Point(mouseX, mouseY)) - return true - } - justPerformedAClickAction = false - lastDraggedButton = null - return false - } - - override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean { - if (super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) return true - - if (initialDragMousePosition.distanceSquared(Vec2f(mouseX.toFloat(), mouseY.toFloat())) >= 4 * 4) { - initialDragMousePosition = Vec2f(-10F, -10F) - lastDraggedButton?.let { dragging -> - justPerformedAClickAction = true - val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mouseX.toInt(), mouseY.toInt()) - ?: return true - dragging.x = offsetX - dragging.y = offsetY - dragging.anchorRight = anchorRight - dragging.anchorBottom = anchorBottom - } - } - return false - } - - var lastDraggedButton: InventoryButton? = null - var justPerformedAClickAction = false - var initialDragMousePosition = Vec2f(-10F, -10F) - - data class AnchoredCoords( - val anchorRight: Boolean, - val anchorBottom: Boolean, - val offsetX: Int, - val offsetY: Int, - ) - - fun getCoordsForMouse(mx: Int, my: Int): AnchoredCoords? { - if (lastGuiRect.contains(mx, my) || lastGuiRect.contains( - Point( - mx + InventoryButton.dimensions.width, - my + InventoryButton.dimensions.height, - ) - ) - ) return null - - val anchorRight = mx > lastGuiRect.maxX - val anchorBottom = my > lastGuiRect.maxY - var offsetX = mx - if (anchorRight) lastGuiRect.maxX else lastGuiRect.minX - var offsetY = my - if (anchorBottom) lastGuiRect.maxY else lastGuiRect.minY - if (InputUtil.isKeyPressed(MC.window.handle, InputUtil.GLFW_KEY_LEFT_SHIFT)) { - offsetX = MathHelper.floor(offsetX / 20F) * 20 - offsetY = MathHelper.floor(offsetY / 20F) * 20 - } - return AnchoredCoords(anchorRight, anchorBottom, offsetX, offsetY) - } - - override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { - if (super.mouseClicked(mouseX, mouseY, button)) return true - val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) } - if (clickedButton != null) { - lastDraggedButton = clickedButton - initialDragMousePosition = Vec2f(mouseX.toFloat(), mouseY.toFloat()) - return true - } - val mx = mouseX.toInt() - val my = mouseY.toInt() - val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mx, my) ?: return true - buttons.add(InventoryButton(offsetX, offsetY, anchorRight, anchorBottom, null, null)) - justPerformedAClickAction = true - return true - } + inner class Editor(val originalButton: InventoryButton) { + @field:Bind + var command: String = originalButton.command ?: "" + + @field:Bind + var icon: String = originalButton.icon ?: "" + + @Bind + fun getItemIcon(): IItemStack { + save() + return ModernItemStack.of(InventoryButton.getItemForName(icon)) + } + + @Bind + fun delete() { + buttons.removeIf { it === originalButton } + popup = null + } + + fun save() { + originalButton.icon = icon + originalButton.command = command + } + } + + var buttons: MutableList = + InventoryButtons.DConfig.data.buttons.map { it.copy() }.toMutableList() + + override fun close() { + InventoryButtons.DConfig.data.buttons = buttons + InventoryButtons.DConfig.markDirty() + super.close() + } + + override fun init() { + super.init() + addDrawableChild( + ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.load-preset")) { + val t = ClipboardUtils.getTextContents() + val newButtons = InventoryButtonTemplates.loadTemplate(t) + if (newButtons != null) + buttons = moveButtons(newButtons.map { it.copy(command = it.command?.removePrefix("/")) }) + } + .position(lastGuiRect.minX + 10, lastGuiRect.minY + 35) + .width(lastGuiRect.width - 20) + .build() + ) + addDrawableChild( + ButtonWidget.builder(Text.translatable("firmament.inventory-buttons.save-preset")) { + ClipboardUtils.setTextContent(InventoryButtonTemplates.saveTemplate(buttons)) + } + .position(lastGuiRect.minX + 10, lastGuiRect.minY + 60) + .width(lastGuiRect.width - 20) + .build() + ) + } + + private fun moveButtons(buttons: List): MutableList { + val newButtons: MutableList = ArrayList(buttons.size) + val movedButtons = mutableListOf() + for (button in buttons) { + if ((!button.anchorBottom && !button.anchorRight && button.x > 0 && button.y > 0)) { + MC.sendChat(tr("firmament.inventory-buttons.button-moved", + "One of your imported buttons intersects with the inventory and has been moved to the top left.")) + movedButtons.add(button.copy( + x = 0, + y = -InventoryButton.dimensions.width, + anchorRight = false, + anchorBottom = false + )) + } else { + newButtons.add(button) + } + } + var i = 0 + val zeroRect = Rectangle(0, 0, 1, 1) + for (movedButton in movedButtons) { + fun getPosition(button: InventoryButton, index: Int) = + button.copy(x = (index % 10) * InventoryButton.dimensions.width, + y = (index / 10) * -InventoryButton.dimensions.height, + anchorRight = false, anchorBottom = false) + while (true) { + val newPos = getPosition(movedButton, i++) + val newBounds = newPos.getBounds(zeroRect) + if (newButtons.none { it.getBounds(zeroRect).intersects(newBounds) }) { + newButtons.add(newPos) + break + } + } + } + return newButtons + } + + override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) { + super.render(context, mouseX, mouseY, delta) + context.matrices.push() + context.matrices.translate(0f, 0f, -10f) + context.fill(lastGuiRect.minX, lastGuiRect.minY, lastGuiRect.maxX, lastGuiRect.maxY, -1) + context.matrices.pop() + for (button in buttons) { + val buttonPosition = button.getBounds(lastGuiRect) + context.matrices.push() + context.matrices.translate(buttonPosition.minX.toFloat(), buttonPosition.minY.toFloat(), 0F) + button.render(context) + context.matrices.pop() + } + } + + override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + if (super.keyPressed(keyCode, scanCode, modifiers)) return true + if (keyCode == GLFW.GLFW_KEY_ESCAPE) { + close() + return true + } + return false + } + + override fun mouseReleased(mouseX: Double, mouseY: Double, button: Int): Boolean { + if (super.mouseReleased(mouseX, mouseY, button)) return true + val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) } + if (clickedButton != null && !justPerformedAClickAction) { + createPopup(MoulConfigUtils.loadGui("button_editor_fragment", Editor(clickedButton)), Point(mouseX, mouseY)) + return true + } + justPerformedAClickAction = false + lastDraggedButton = null + return false + } + + override fun mouseDragged(mouseX: Double, mouseY: Double, button: Int, deltaX: Double, deltaY: Double): Boolean { + if (super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) return true + + if (initialDragMousePosition.distanceSquared(Vec2f(mouseX.toFloat(), mouseY.toFloat())) >= 4 * 4) { + initialDragMousePosition = Vec2f(-10F, -10F) + lastDraggedButton?.let { dragging -> + justPerformedAClickAction = true + val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mouseX.toInt(), mouseY.toInt()) + ?: return true + dragging.x = offsetX + dragging.y = offsetY + dragging.anchorRight = anchorRight + dragging.anchorBottom = anchorBottom + } + } + return false + } + + var lastDraggedButton: InventoryButton? = null + var justPerformedAClickAction = false + var initialDragMousePosition = Vec2f(-10F, -10F) + + data class AnchoredCoords( + val anchorRight: Boolean, + val anchorBottom: Boolean, + val offsetX: Int, + val offsetY: Int, + ) + + fun getCoordsForMouse(mx: Int, my: Int): AnchoredCoords? { + if (lastGuiRect.contains(mx, my) || lastGuiRect.contains( + Point( + mx + InventoryButton.dimensions.width, + my + InventoryButton.dimensions.height, + ) + ) + ) return null + + val anchorRight = mx > lastGuiRect.maxX + val anchorBottom = my > lastGuiRect.maxY + var offsetX = mx - if (anchorRight) lastGuiRect.maxX else lastGuiRect.minX + var offsetY = my - if (anchorBottom) lastGuiRect.maxY else lastGuiRect.minY + if (InputUtil.isKeyPressed(MC.window.handle, InputUtil.GLFW_KEY_LEFT_SHIFT)) { + offsetX = MathHelper.floor(offsetX / 20F) * 20 + offsetY = MathHelper.floor(offsetY / 20F) * 20 + } + return AnchoredCoords(anchorRight, anchorBottom, offsetX, offsetY) + } + + override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { + if (super.mouseClicked(mouseX, mouseY, button)) return true + val clickedButton = buttons.firstOrNull { it.getBounds(lastGuiRect).contains(Point(mouseX, mouseY)) } + if (clickedButton != null) { + lastDraggedButton = clickedButton + initialDragMousePosition = Vec2f(mouseX.toFloat(), mouseY.toFloat()) + return true + } + val mx = mouseX.toInt() + val my = mouseY.toInt() + val (anchorRight, anchorBottom, offsetX, offsetY) = getCoordsForMouse(mx, my) ?: return true + buttons.add(InventoryButton(offsetX, offsetY, anchorRight, anchorBottom, null, null)) + justPerformedAClickAction = true + return true + } } diff --git a/src/main/kotlin/features/inventory/buttons/InventoryButtonTemplates.kt b/src/main/kotlin/features/inventory/buttons/InventoryButtonTemplates.kt index 99b544b..d282157 100644 --- a/src/main/kotlin/features/inventory/buttons/InventoryButtonTemplates.kt +++ b/src/main/kotlin/features/inventory/buttons/InventoryButtonTemplates.kt @@ -1,35 +1,33 @@ - - package moe.nea.firmament.features.inventory.buttons -import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import net.minecraft.text.Text import moe.nea.firmament.Firmament +import moe.nea.firmament.util.ErrorUtil import moe.nea.firmament.util.MC import moe.nea.firmament.util.TemplateUtil object InventoryButtonTemplates { - val legacyPrefix = "NEUBUTTONS/" - val modernPrefix = "MAYBEONEDAYIWILLHAVEMYOWNFORMAT" + val legacyPrefix = "NEUBUTTONS/" + val modernPrefix = "MAYBEONEDAYIWILLHAVEMYOWNFORMAT" - fun loadTemplate(t: String): List? { - val buttons = TemplateUtil.maybeDecodeTemplate>(legacyPrefix, t) ?: return null - return buttons.mapNotNull { - try { - Firmament.json.decodeFromString(it).also { - if (it.icon?.startsWith("extra:") == true || it.command?.any { it.isLowerCase() } == true) { - MC.sendChat(Text.translatable("firmament.inventory-buttons.import-failed")) - } - } - } catch (e: Exception) { - null - } - } - } + fun loadTemplate(t: String): List? { + val buttons = TemplateUtil.maybeDecodeTemplate>(legacyPrefix, t) ?: return null + return buttons.mapNotNull { + ErrorUtil.catch("Could not import button") { + Firmament.json.decodeFromString(it).also { + if (it.icon?.startsWith("extra:") == true) { + MC.sendChat(Text.translatable("firmament.inventory-buttons.import-failed")) + } + } + }.or { + null + } + } + } - fun saveTemplate(buttons: List): String { - return TemplateUtil.encodeTemplate(legacyPrefix, buttons.map { Firmament.json.encodeToString(it) }) - } + fun saveTemplate(buttons: List): String { + return TemplateUtil.encodeTemplate(legacyPrefix, buttons.map { Firmament.json.encodeToString(it) }) + } } -- cgit