aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/utils/renderables/DragNDrop.kt
blob: 70cab119e77950cfaff7e855daf30366d2f325e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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<ItemStack> {

    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<T> {

    fun get(): T
    fun onRender(mouseX: Int, mouseY: Int)

}

interface Droppable {

    fun handle(drop: Any?)
    fun validTarget(item: Any?): Boolean
}