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 · 131 行raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
package com.odtheking.odin.clickgui.widget

import com.odtheking.odin.OdinMod.mc
import com.odtheking.odin.clickgui.GuiTheme
import com.odtheking.odin.clickgui.blend
import com.odtheking.odin.clickgui.settings.RenderableSetting
import com.odtheking.odin.features.Module
import com.odtheking.odin.utils.Color.Companion.brighter
import com.odtheking.odin.utils.Color.Companion.darker
import com.odtheking.odin.utils.Colors
import com.odtheking.odin.utils.render.clipped
import com.odtheking.odin.utils.render.scissoredReveal
import com.odtheking.odin.utils.ui.animations.Easing
import com.odtheking.odin.utils.ui.animations.Fade
import net.minecraft.client.gui.GuiGraphicsExtractor
import net.minecraft.client.gui.components.events.GuiEventListener
import net.minecraft.client.input.MouseButtonEvent
import net.minecraft.network.chat.Component

class ModuleWidget(val module: Module) : OdinContainerWidget(0, 0, GuiTheme.ROW_WIDTH, GuiTheme.ROW_HEIGHT, Component.literal(module.name)) {
    private val header = ModuleHeaderWidget(this, module)
    private val settings = module.settings.values.filterIsInstance<RenderableSetting<*>>()

    private val elements: List<GuiEventListener> = listOf(header) + settings
    private val headerOnly: List<GuiEventListener> = listOf(header)

    private val expand = Fade(EXPAND_DURATION, Easing.EASE_IN_OUT)
    private val filter = Fade(FILTER_DURATION, Easing.EASE_IN_OUT, initial = true)

    private var revealed = 0
    val expanded: Boolean get() = expand.current

    private var shown = 1f

    val isFiltering: Boolean get() = filter.isAnimating

    override fun children(): List<GuiEventListener> = if (expanded) elements else headerOnly

    fun matches(search: String): Boolean {
        shown = filter.progress(module.name.contains(search, true))
        return shown > 0f
    }

    fun toggleExpanded() {
        if (settings.isNotEmpty()) expand.toggle()
    }

    fun release() = settings.forEach { it.release() }

    fun measure() {
        val progress = expand.progress()

        var content = 0
        for (widget in settings) {
            val reveal = widget.revealFraction
            widget.visible = progress > 0f && reveal > 0f
            if (!widget.visible) continue
            widget.measure()
            content += (widget.height * reveal).toInt()
        }

        revealed = (progress * content).toInt()
        height = ((GuiTheme.ROW_HEIGHT + revealed) * shown).toInt()
    }

    fun place() {
        header.x = x
        header.y = y

        var offset = GuiTheme.ROW_HEIGHT
        for (widget in settings) {
            if (!widget.visible) continue
            widget.x = x
            widget.y = y + offset
            widget.place()
            offset += (widget.height * widget.revealFraction).toInt()
        }
    }

    override fun render(graphics: GuiGraphicsExtractor, mouseX: Int, mouseY: Int) {
        val squeezed = height < GuiTheme.ROW_HEIGHT + revealed
        graphics.clipped(squeezed, x, y, x + width, y + height) {
            header.extractRenderState(graphics, mouseX, mouseY, 0f)

            graphics.scissoredReveal(x, y + GuiTheme.ROW_HEIGHT, x + width, revealed) {
                for (widget in settings) {
                    if (!widget.visible) continue
                    val fraction = widget.revealFraction
                    graphics.clipped(fraction < 1f, widget.x, widget.y, widget.x + widget.width, widget.y + (widget.height * fraction).toInt()) {
                        widget.extractRenderState(graphics, mouseX, mouseY, 0f)
                    }
                }
            }
        }
    }

    private companion object {
        const val EXPAND_DURATION = 250L
        const val FILTER_DURATION = 150L
    }
}

private class ModuleHeaderWidget(private val group: ModuleWidget, private val module: Module) : OdinWidget(
    0, 0, GuiTheme.ROW_WIDTH, GuiTheme.ROW_HEIGHT, Component.literal(module.name)
) {
    override val clickButtons = BOTH_BUTTONS
    override val description = module.description

    private val enabledFade = Fade(ENABLED_DURATION)

    override fun render(graphics: GuiGraphicsExtractor, mouseX: Int, mouseY: Int) {
        val toggled = enabledFade.progress(module.enabled)
        var color = blend(GuiTheme.background.rgba, GuiTheme.accent.rgba, toggled)

        val hovered = hover
        if (hovered > 0f)
            color = blend(color, blend(GuiTheme.background.brighter(1.4f).rgba, GuiTheme.accent.darker(0.8f).rgba, toggled), hovered)

        graphics.fill(x, y, x + width, y + height, color)
        graphics.centeredText(mc.font, module.name, x + width / 2, GuiTheme.textY(y, height), Colors.WHITE.rgba)
    }

    override fun onClick(event: MouseButtonEvent, doubleClick: Boolean) {
        if (event.button() == RIGHT) group.toggleExpanded() else module.toggle()
    }

    private companion object {
        const val ENABLED_DURATION = 150L
    }
}