Finish remaking UI rendering

Signed-off-by: Username404-59 <w.iron.zombie@gmail.com>
This commit is contained in:
Username404-59 2026-02-06 01:35:50 +01:00
parent a20a2d2d8c
commit 174f840226
Signed by: Username404-59
GPG Key ID: 7AB361FBB257A5D1
3 changed files with 108 additions and 25 deletions

View File

@ -6,6 +6,7 @@ import fr.username404.snowygui.gui.SnowyScreen
import fr.username404.snowygui.gui.elements.ClickBox import fr.username404.snowygui.gui.elements.ClickBox
import net.minecraft.client.input.MouseButtonEvent import net.minecraft.client.input.MouseButtonEvent
import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW
import kotlin.math.roundToInt
object ClickGui: SnowyScreen() { object ClickGui: SnowyScreen() {
override val components = mutableSetOf<Element>() override val components = mutableSetOf<Element>()
@ -18,8 +19,8 @@ object ClickGui: SnowyScreen() {
private var draggingBox: String? = null private var draggingBox: String? = null
private inline fun currentBoxContext(args: ClickBox.() -> Unit): Unit? = draggingBox?.run { boxContext { if (name.string == draggingBox) args() } } private inline fun currentBoxContext(args: ClickBox.() -> Unit): Unit? = draggingBox?.run { boxContext { if (name.string == draggingBox) args() } }
private var offsetX: Double = 0.0; private var offsetX: Double = 0.0
private var offsetY: Double = 0.0; private var offsetY: Double = 0.0
override fun mouseClicked(event: MouseButtonEvent, isDoubleClick: Boolean): Boolean { override fun mouseClicked(event: MouseButtonEvent, isDoubleClick: Boolean): Boolean {
if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
clickBoxes.find { it.isWithinBounds(event.x, event.y) }?.let { draggingBox = it.name.string } clickBoxes.find { it.isWithinBounds(event.x, event.y) }?.let { draggingBox = it.name.string }
@ -36,8 +37,12 @@ object ClickGui: SnowyScreen() {
override fun mouseDragged(event: MouseButtonEvent, mouseX: Double, mouseY: Double): Boolean { override fun mouseDragged(event: MouseButtonEvent, mouseX: Double, mouseY: Double): Boolean {
if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) { if (event.input() == GLFW.GLFW_MOUSE_BUTTON_LEFT) {
currentBoxContext { currentBoxContext {
x = (event.x + offsetX).coerceIn(0.0..this@ClickGui.width - width.toDouble()) val targetX = (event.x + offsetX).coerceIn(0.0..this@ClickGui.width - width.toDouble())
y = (event.y + offsetY).coerceIn(0.0..this@ClickGui.height - height.toDouble()) val targetY = (event.y + offsetY).coerceIn(0.0..this@ClickGui.height - height.toDouble())
// Snap to integer pixels => stable spacing
x = targetX.roundToInt().toDouble()
y = targetY.roundToInt().toDouble()
} }
} }
return super.mouseDragged(event, mouseX, mouseY) return super.mouseDragged(event, mouseX, mouseY)

View File

@ -12,10 +12,11 @@ import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.util.ARGB import net.minecraft.util.ARGB
import kotlin.math.floor
import kotlin.math.roundToInt
import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.ApiStatus
import java.util.TreeSet import java.util.TreeSet
import kotlin.collections.LinkedHashSet import kotlin.collections.LinkedHashSet
import kotlin.math.roundToInt
@ApiStatus.Internal @ApiStatus.Internal
class ClickBox( class ClickBox(
@ -74,13 +75,17 @@ class ClickBox(
} }
override fun render(guiGraphics: GuiGraphics?) { override fun render(guiGraphics: GuiGraphics?) {
val xi = floor(x).toInt()
val yi = floor(y).toInt()
// Header // Header
RenderingUtil.drawRectangle( RenderingUtil.drawSlantedHeader(
guiGraphics = guiGraphics, guiGraphics = guiGraphics,
x = x, x = xi,
y = y, y = yi,
height = height,
width = width, width = width,
height = height,
slantTop = inclination,
color = color, color = color,
opacity = opacity opacity = opacity
) )
@ -88,8 +93,8 @@ class ClickBox(
// Body // Body
RenderingUtil.drawRectangle( RenderingUtil.drawRectangle(
guiGraphics = guiGraphics, guiGraphics = guiGraphics,
x = x, x = xi.toDouble(),
y = (y + height), y = (yi + height).toDouble(),
height = clickboxHeightOffset, height = clickboxHeightOffset,
width = width + inclination.roundToInt(), width = width + inclination.roundToInt(),
color = color, color = color,
@ -99,24 +104,36 @@ class ClickBox(
// Separator line // Separator line
RenderingUtil.hLine( RenderingUtil.hLine(
guiGraphics = guiGraphics, guiGraphics = guiGraphics,
x1 = (x + inclination).toInt(), x1 = (xi + inclination).toInt(),
x2 = (x + width).toInt(), x2 = (xi + width),
y = (y + height).toInt(), y = (yi + height),
rgb = Colors.WHITE_LINES.hexValue, rgb = Colors.WHITE_LINES.hexValue,
opacity = 1f opacity = 1f
) )
if (buttons.isNotEmpty()) { if (buttons.isNotEmpty()) {
val barWidth = 3
val leftPadding = 3
val gapToBar = 1
buttonsProgressBar.apply { buttonsProgressBar.apply {
this.x = this@ClickBox.x + this@ClickBox.width - 3 this.width = barWidth
this.x = this@ClickBox.x + this@ClickBox.width - barWidth
this.y = this@ClickBox.y + this@ClickBox.height + 3 this.y = this@ClickBox.y + this@ClickBox.height + 3
}.display(guiGraphics) }.display(guiGraphics)
val buttonWidth = (this@ClickBox.width - leftPadding - barWidth - gapToBar).coerceAtLeast(10)
buttons.forEachIndexed { num, button -> buttons.forEachIndexed { num, button ->
val fullHeight = (y + height.toDouble())..(this.y + height + clickboxHeightOffset) val fullHeight = (y + height.toDouble())..(this.y + height + clickboxHeightOffset)
button.also { button.also {
it.x = this.x + 3 it.x = this.x + leftPadding
it.y = this.y + 3 + height + (((num + 1) - barStage) * 9) it.y = this.y + 3 + height + (((num + 1) - barStage) * 9)
it.hidden = if ((num + 1) <= 8) ((it.y) !in fullHeight) else ((it.y + it.height) !in fullHeight)
it.width = buttonWidth
it.hidden =
if ((num + 1) <= 8) ((it.y) !in fullHeight)
else ((it.y + it.height) !in fullHeight)
}.display(guiGraphics) }.display(guiGraphics)
} }
} }
@ -125,8 +142,9 @@ class ClickBox(
guiGraphics?.drawString( guiGraphics?.drawString(
this, this,
Component.nullToEmpty(name.string), Component.nullToEmpty(name.string),
(x + 5).toInt(), (y + 2).toInt(), (xi + 5 + (inclination / 2f)).toInt(),
ARGB.opaque(Colors.TRANSPARENT.hexValue), (yi + 2),
ARGB.opaque(Colors.WHITE.hexValue),
false false
) )
} }

View File

@ -4,6 +4,10 @@ import com.mojang.blaze3d.opengl.GlStateManager
import fr.username404.snowygui.gui.feature.Colors import fr.username404.snowygui.gui.feature.Colors
import net.minecraft.client.gui.GuiGraphics import net.minecraft.client.gui.GuiGraphics
import net.minecraft.util.ARGB import net.minecraft.util.ARGB
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.min
object RenderingUtil { object RenderingUtil {
fun prepareDraw() = GlStateManager._enableBlend() fun prepareDraw() = GlStateManager._enableBlend()
@ -27,18 +31,74 @@ object RenderingUtil {
color: Int = Colors.TRANSPARENT(), color: Int = Colors.TRANSPARENT(),
opacity: Float = 1F opacity: Float = 1F
) { ) {
if (guiGraphics == null) return
val x1 = floor(x).toInt()
val y1 = floor(y).toInt()
val x2 = ceil(x + width).toInt()
val y2 = ceil(y + height).toInt()
prepareDraw() prepareDraw()
guiGraphics?.fill( guiGraphics.fill(x1, y1, x2, y2, argbFromRgb(color, opacity))
x.toInt(), y.toInt(), endDraw()
(x + width).toInt(), (y + height).toInt(), }
argbFromRgb(color, opacity)
) fun drawSlantedHeader(
guiGraphics: GuiGraphics?,
x: Int,
y: Int,
width: Int,
height: Int,
slantTop: Float,
color: Int,
opacity: Float
) {
if (guiGraphics == null) return
if (width <= 0 || height <= 0) return
val slant = slantTop.toDouble()
val baseArgb = argbFromRgb(color, opacity)
prepareDraw()
for (dy in 0 until height) {
val t = if (height == 1) 0.0 else dy.toDouble() / (height - 1).toDouble()
val leftF = x + slant * (1.0 - t)
val rightF = x + width + slant * t
val left = min(leftF, rightF)
val right = max(leftF, rightF)
val lx = floor(left).toInt()
val rx = floor(right).toInt()
val yy = y + dy
val midStart = lx + 1
val midEnd = rx
if (midEnd > midStart) {
guiGraphics.fill(midStart, yy, midEnd, yy + 1, baseArgb)
}
val leftFrac = (left - floor(left)).toFloat().coerceIn(0f, 1f)
val rightFrac = (right - floor(right)).toFloat().coerceIn(0f, 1f)
val leftAlpha = (1f - leftFrac) * opacity
val rightAlpha = rightFrac * opacity
if (leftAlpha > 0f) guiGraphics.fill(lx, yy, lx + 1, yy + 1, argbFromRgb(color, leftAlpha))
if (rightAlpha > 0f) guiGraphics.fill(rx, yy, rx + 1, yy + 1, argbFromRgb(color, rightAlpha))
if (rx <= lx) {
guiGraphics.fill(lx, yy, lx + 1, yy + 1, baseArgb)
}
}
endDraw() endDraw()
} }
fun hLine(guiGraphics: GuiGraphics?, x1: Int, x2: Int, y: Int, rgb: Int, opacity: Float = 1f) { fun hLine(guiGraphics: GuiGraphics?, x1: Int, x2: Int, y: Int, rgb: Int, opacity: Float = 1f) {
if (guiGraphics == null) return
prepareDraw() prepareDraw()
guiGraphics?.hLine(x1, x2, y, argbFromRgb(rgb, opacity)) guiGraphics.hLine(x1, x2, y, argbFromRgb(rgb, opacity))
endDraw() endDraw()
} }
} }