HTTPS
https://git.nageyqma.icu/nageyqma/odin_next.git
SSH
git@git.nageyqma.icu:nageyqma/odin_next.git
HTTPS 链接可直接 git clone;推送代码请使用 SSH。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
package com.odtheking.odin.clickgui.widget
import com.odtheking.odin.OdinMod.mc
import com.odtheking.odin.clickgui.ClickGUI
import com.odtheking.odin.clickgui.GuiTheme
import com.odtheking.odin.features.Category
import com.odtheking.odin.features.ModuleManager
import com.odtheking.odin.features.impl.render.ClickGUIModule
import com.odtheking.odin.utils.Colors
import com.odtheking.odin.utils.render.Corners
import com.odtheking.odin.utils.render.roundedRect
import com.odtheking.odin.utils.render.roundedShadow
import com.odtheking.odin.utils.render.scissored
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
import kotlin.math.sign
class PanelWidget(category: Category) : OdinContainerWidget(
0, 0, GuiTheme.ROW_WIDTH, GuiTheme.ROW_HEIGHT + GuiTheme.CAP, Component.literal(category.name)
) {
private val panelData = ClickGUIModule.panelSetting.getOrPut(category.name) { ClickGUIModule.PanelData(0, 0) }
private val boldTitle = "§l${category.name}"
private val modules = ModuleManager.modulesByCategory[category]
?.sortedByDescending { mc.font.width(it.name) }
?.map { ModuleWidget(it) }.orEmpty()
override fun children(): List<GuiEventListener> = modules
private var contentHeight = 0
private var scroll = 0
private var headerGrabbed = false
private var grabX = 0
private var grabY = 0
var extended: Boolean
get() = panelData.extended
set(value) {
panelData.extended = value
if (!value) {
scroll = 0
modules.forEach { it.visible = false }
}
}
fun moveTo(newX: Int, newY: Int) {
panelData.x = newX.coerceIn(0, maxX)
panelData.y = newY.coerceIn(0, maxY)
}
private val maxX get() = (ClickGUI.virtualWidth - GuiTheme.ROW_WIDTH).coerceAtLeast(0)
private val maxY get() = (ClickGUI.virtualHeight - GuiTheme.ROW_HEIGHT).coerceAtLeast(0)
fun release() = modules.forEach { it.release() }
fun resetScroll() {
scroll = 0
}
override fun render(graphics: GuiGraphicsExtractor, mouseX: Int, mouseY: Int) {
layout()
graphics.roundedShadow(x, y, x + width, y + height, GuiTheme.shadow.rgba, GuiTheme.PANEL_BLUR, CORNERS)
graphics.roundedRect(x, y, x + width, y + GuiTheme.ROW_HEIGHT, GuiTheme.background.rgba, CORNERS_TOP)
graphics.centeredText(mc.font, boldTitle, x + width / 2, GuiTheme.textY(y, GuiTheme.ROW_HEIGHT), Colors.WHITE.rgba)
val capY = y + height - GuiTheme.CAP
if (extended) {
val top = y + GuiTheme.ROW_HEIGHT
graphics.scissored(x, top, x + width, capY) {
for (module in modules) {
if (!module.visible || module.bottom <= top || module.y >= capY) continue
module.extractRenderState(graphics, mouseX, mouseY, 0f)
}
}
}
graphics.roundedRect(
x, capY, x + width, capY + GuiTheme.CAP,
(if (modules.lastOrNull()?.module?.enabled == true && extended) GuiTheme.accent else GuiTheme.background).rgba,
CORNERS_BOTTOM
)
}
override fun onClick(event: MouseButtonEvent, doubleClick: Boolean) {
headerGrabbed = event.y().toInt() < y + GuiTheme.ROW_HEIGHT
if (!headerGrabbed) return
if (event.button() == RIGHT) {
extended = !extended
return
}
grabX = event.x().toInt() - x
grabY = event.y().toInt() - y
}
override fun onDrag(event: MouseButtonEvent, dragX: Double, dragY: Double) {
if (headerGrabbed) moveTo(event.x().toInt() - grabX, event.y().toInt() - grabY)
}
override fun mouseScrolled(mouseX: Double, mouseY: Double, scrollX: Double, scrollY: Double): Boolean {
if (!extended || !isMouseOver(mouseX, mouseY)) return false
val limit = (contentHeight - MIN_VISIBLE).coerceAtLeast(0)
scroll = (scroll + (scrollY.sign * SCROLL_STEP).toInt()).coerceIn(-limit, 0)
return true
}
private fun layout() {
x = panelData.x.coerceIn(0, maxX)
y = panelData.y.coerceIn(0, maxY)
if (!extended) {
height = GuiTheme.ROW_HEIGHT + GuiTheme.CAP
return
}
contentHeight = 0
var filtering = false
for (module in modules) {
module.visible = module.matches(ClickGUI.searchString)
filtering = filtering || module.isFiltering
if (!module.visible) continue
module.measure()
contentHeight += module.height
}
if (!filtering) scroll = scroll.coerceIn(-(contentHeight - MIN_VISIBLE).coerceAtLeast(0), 0)
var offset = GuiTheme.ROW_HEIGHT + scroll
for (module in modules) {
if (!module.visible) continue
module.x = x
module.y = y + offset
module.place()
offset += module.height
}
height = offset + GuiTheme.CAP
}
private companion object {
const val MIN_VISIBLE = 72
const val SCROLL_STEP = 16
val CORNERS = Corners(GuiTheme.RADIUS)
val CORNERS_TOP = Corners.top(GuiTheme.RADIUS)
val CORNERS_BOTTOM = Corners.bottom(GuiTheme.RADIUS)
}
}