nageyqma·git
HTTPS https://git.nageyqma.icu/nageyqma/odin_next.git SSH git@git.nageyqma.icu:nageyqma/odin_next.git

HTTPS 链接可直接 git clone;推送代码请使用 SSH。

4.8 KB · 115 行raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
package com.odtheking.odin.clickgui.widget

import com.odtheking.odin.clickgui.ClickGUI
import com.odtheking.odin.utils.ui.animations.Fade
import net.minecraft.client.gui.ComponentPath
import net.minecraft.client.gui.GuiGraphicsExtractor
import net.minecraft.client.gui.components.AbstractWidget
import net.minecraft.client.gui.components.events.ContainerEventHandler
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.gui.narration.NarrationElementOutput
import net.minecraft.client.gui.navigation.FocusNavigationEvent
import net.minecraft.client.input.MouseButtonEvent
import net.minecraft.client.input.MouseButtonInfo
import net.minecraft.client.sounds.SoundManager
import net.minecraft.network.chat.Component

abstract class OdinWidget(x: Int, y: Int, width: Int, height: Int, message: Component) : AbstractWidget(x, y, width, height, message) {
    private val hoverFade = Fade(HOVER_DURATION)
    private val descriptionDelay = Fade(DESCRIPTION_DELAY, settles = false)

    private var boundsHovered = false

    protected open val clickButtons = LEFT_ONLY
    protected open val description get() = ""

    protected val hover get() = hoverFade.progress(boundsHovered)

    final override fun isValidClickButton(buttonInfo: MouseButtonInfo): Boolean = buttonInfo.button() in clickButtons

    final override fun extractWidgetRenderState(graphics: GuiGraphicsExtractor, mouseX: Int, mouseY: Int, partialTick: Float) {
        boundsHovered = visible && isOver(mouseX, mouseY, x, y, width, height)

        render(graphics, mouseX, mouseY)

        val resting = wantsDescription(mouseX, mouseY)
        if (description.isNotEmpty() && resting && descriptionDelay.progress(true) >= 1f)
            ClickGUI.setDescription(description, right + DESCRIPTION_GAP, y)
        else if (!resting) descriptionDelay.progress(false)
    }

    protected open fun wantsDescription(mouseX: Int, mouseY: Int): Boolean = boundsHovered

    protected abstract fun render(graphics: GuiGraphicsExtractor, mouseX: Int, mouseY: Int)
    override fun playDownSound(soundManager: SoundManager) = Unit
    override fun updateWidgetNarration(output: NarrationElementOutput) = defaultButtonNarrationText(output)

    companion object {
        const val LEFT = 0
        const val RIGHT = 1

        val LEFT_ONLY = intArrayOf(LEFT)
        val BOTH_BUTTONS = intArrayOf(LEFT, RIGHT)

        private const val HOVER_DURATION = 150L
        private const val DESCRIPTION_DELAY = 600L
        private const val DESCRIPTION_GAP = 10
    }
}

abstract class OdinContainerWidget(x: Int, y: Int, width: Int, height: Int, message: Component) : OdinWidget(x, y, width, height, message), ContainerEventHandler {
    private var focusedChild: GuiEventListener? = null
    private var draggingChild = false
    private var selfFocused = false

    override val clickButtons: IntArray = BOTH_BUTTONS
    abstract override fun children(): List<GuiEventListener>
    override fun getFocused(): GuiEventListener? = focusedChild

    override fun setFocused(listener: GuiEventListener?) {
        if (focusedChild === listener) return
        focusedChild?.isFocused = false
        listener?.isFocused = true
        focusedChild = listener
    }

    override fun isDragging(): Boolean = draggingChild

    override fun setDragging(dragging: Boolean) {
        draggingChild = dragging
    }

    override fun isFocused(): Boolean = selfFocused || focusedChild != null

    override fun setFocused(focused: Boolean) {
        selfFocused = focused
        if (!focused) setFocused(null)
    }

    override fun nextFocusPath(event: FocusNavigationEvent): ComponentPath? =
        super<ContainerEventHandler>.nextFocusPath(event)

    override fun mouseClicked(event: MouseButtonEvent, doubleClick: Boolean): Boolean =
        super<ContainerEventHandler>.mouseClicked(event, doubleClick) ||
            super<OdinWidget>.mouseClicked(event, doubleClick)

    override fun mouseReleased(event: MouseButtonEvent): Boolean =
        super<ContainerEventHandler>.mouseReleased(event) || super<OdinWidget>.mouseReleased(event)

    override fun mouseDragged(event: MouseButtonEvent, dragX: Double, dragY: Double): Boolean =
        super<ContainerEventHandler>.mouseDragged(event, dragX, dragY) ||
            super<OdinWidget>.mouseDragged(event, dragX, dragY)

    override fun render(graphics: GuiGraphicsExtractor, mouseX: Int, mouseY: Int) {
        renderChildren(graphics, mouseX, mouseY)
    }

    protected fun renderChildren(graphics: GuiGraphicsExtractor, mouseX: Int, mouseY: Int) {
        for (child in children()) {
            if (child is AbstractWidget) child.extractRenderState(graphics, mouseX, mouseY, 0f)
        }
    }
}

internal fun isOver(mouseX: Int, mouseY: Int, x: Int, y: Int, width: Int, height: Int): Boolean =
    mouseX >= x && mouseX < x + width && mouseY >= y && mouseY < y + height