From 739a48d4679ce05c1f555a04fcdaa4e509d59d5d Mon Sep 17 00:00:00 2001 From: Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com> Date: Sun, 23 Jun 2024 20:18:45 +0200 Subject: Backend: Drag and Drop for Renderables (#1864) Co-authored-by: Cal Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../skyhanni/utils/renderables/DragNDrop.kt | 106 +++++++++++++++++++++ .../skyhanni/utils/renderables/Renderable.kt | 2 +- .../skyhanni/utils/renderables/RenderableUtils.kt | 7 ++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/utils/renderables/DragNDrop.kt (limited to 'src/main/java/at/hannibal2/skyhanni/utils') diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/DragNDrop.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/DragNDrop.kt new file mode 100644 index 000000000..70cab119e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/DragNDrop.kt @@ -0,0 +1,106 @@ +package at.hannibal2.skyhanni.utils.renderables + +import at.hannibal2.skyhanni.events.GuiContainerEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.init.Blocks +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object DragNDrop { + + private var currentDrag: DragItem<*>? = null + + private var isInvalidDrop = false + + private const val BUTTON = 0 + + private const val BUTTON_MAPPED = BUTTON - 100 + + private val invalidItem = Renderable.itemStack(ItemStack(Blocks.barrier), 1.0) + + @SubscribeEvent + fun onGuiContainerBeforeDraw(event: GuiContainerEvent.PreDraw) { + isInvalidDrop = false + } + + @SubscribeEvent + fun onGuiContainerAfterDraw(event: GuiContainerEvent.PostDraw) { + val item = currentDrag ?: return + if (!BUTTON_MAPPED.isKeyHeld()) { + currentDrag = null + return + } + GlStateManager.translate(event.mouseX.toFloat(), event.mouseY.toFloat(), 0f) + if (isInvalidDrop) { + invalidItem.render(event.mouseX, event.mouseY) + } else { + item.onRender(event.mouseX, event.mouseY) + } + GlStateManager.translate(-event.mouseX.toFloat(), -event.mouseY.toFloat(), 0f) + } + + fun draggable( + display: Renderable, + item: () -> DragItem<*>, + bypassChecks: Boolean = false, + condition: () -> Boolean = { true }, + ) = Renderable.clickable( + display, + onClick = { currentDrag = item() }, + button = BUTTON, + bypassChecks = bypassChecks, + condition = condition, + ) + + fun droppable( + display: Renderable, + drop: Droppable, + bypassChecks: Boolean = false, + condition: () -> Boolean = { true }, + ): Renderable = object : RenderableWrapper(display) { + override fun render(posX: Int, posY: Int) { + if (isHovered(posX, posY) && condition() && Renderable.shouldAllowLink(true, bypassChecks)) { + handelDroppable(drop) + } + content.render(posX, posY) + } + } + + private fun handelDroppable(drop: Droppable) { + val item = currentDrag ?: return + if (drop.validTarget(item.get())) { + if (!BUTTON_MAPPED.isKeyHeld()) { + drop.handle(item.get()) + currentDrag = null + } + } else { + isInvalidDrop = true + } + + } +} + +fun ItemStack.toDragItem(scale: Double = 1.0) = object : DragItem { + + val render = Renderable.itemStack(this@toDragItem, scale, 0) + + override fun get(): ItemStack = this@toDragItem + + override fun onRender(mouseX: Int, mouseY: Int) = render.render(mouseX, mouseY) +} + +interface DragItem { + + fun get(): T + fun onRender(mouseX: Int, mouseY: Int) + +} + +interface Droppable { + + fun handle(drop: Any?) + fun validTarget(item: Any?): Boolean +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt index f00cba6c5..0ed562152 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -233,7 +233,7 @@ interface Renderable { } } - private fun shouldAllowLink(debug: Boolean = false, bypassChecks: Boolean): Boolean { + internal fun shouldAllowLink(debug: Boolean = false, bypassChecks: Boolean): Boolean { val guiScreen = Minecraft.getMinecraft().currentScreen val isGuiScreen = guiScreen != null diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt index d1a8aae02..a78044d72 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt @@ -73,3 +73,10 @@ internal object RenderableUtils { return yOffset } } + +internal abstract class RenderableWrapper internal constructor(protected val content: Renderable) : Renderable { + override val width = content.width + override val height = content.height + override val horizontalAlign = content.horizontalAlign + override val verticalAlign = content.verticalAlign +} -- cgit