diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt index 64d52ae70..25923bc19 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt @@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.client.render.TextAlign import ru.dbotthepony.mc.otm.client.render.drawAligned import ru.dbotthepony.mc.otm.client.render.drawRect import ru.dbotthepony.mc.otm.client.render.tesselator +import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.math.RGBAColor @@ -144,6 +145,11 @@ open class TextInputPanel( open var backgroundColor = RGBAColor.BLACK open var isActive = true + init { + scissor = true + dockPadding = DockProperty(2f, 2f, 2f, 2f) + } + private var oldText = ArrayList() private var textCache: String? = null private val lines = ArrayList() @@ -968,12 +974,21 @@ open class TextInputPanel( return true } + open fun acceptsCharacter(codepoint: Char, mods: Int = 0): Boolean { + return true + } + override fun charTypedInternal(codepoint: Char, mods: Int): Boolean { if (!isActive) { killFocus() return true } + if (!acceptsCharacter(codepoint, mods)) { + playGuiClickSound() + return true + } + wipeSelection() if (!multiLine) @@ -1003,9 +1018,10 @@ open class TextInputPanel( } override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) { - drawRect(stack, 0f, 0f, width, height, backgroundColor) + if (!backgroundColor.isFullyTransparent) + drawRect(stack, 0f, 0f, width, height, backgroundColor) - var y = 0f + var y = dockPadding.top for ((i, line) in lines.withIndex()) { val selection = selections[i] @@ -1015,7 +1031,7 @@ open class TextInputPanel( buffer = BUFFER, text = line, align = TextAlign.TOP_LEFT, - x = 0f, + x = dockPadding.left, y = y, color = textColor ) @@ -1023,10 +1039,10 @@ open class TextInputPanel( if (selection != null && selection.isValid) { val (before, selected) = selection.sub(line) - var x = 0f + var x = dockPadding.left if (before.isNotEmpty()) { - x = font.width(before).toFloat() + x += font.width(before).toFloat() } val width = if (selection.coversNewline(line) && i != lines.size - 1) this.width - x else font.width(selected).toFloat() @@ -1057,6 +1073,9 @@ open class TextInputPanel( } y += font.lineHeight + 2f + + if (y > height - dockPadding.bottom) + break } if (isFocused && milliTime % 1000L > 500L) { @@ -1068,8 +1087,8 @@ open class TextInputPanel( buffer = BUFFER, text = "_", align = TextAlign.TOP_LEFT, - x = if (activeLine == null) 0f else font.width(activeLine).toFloat(), - y = cursorLine * (font.lineHeight + 2f), + x = dockPadding.left + (if (activeLine == null) 0f else font.width(activeLine).toFloat()), + y = dockPadding.top + cursorLine * (font.lineHeight + 2f), color = cursorColor ) } else { @@ -1078,8 +1097,8 @@ open class TextInputPanel( buffer = BUFFER, text = "|", align = TextAlign.TOP_LEFT, - x = font.width(activeLine.substring(0, cursorCharacter)).toFloat() - 1f, - y = cursorLine * (font.lineHeight + 2f), + x = dockPadding.left + font.width(activeLine.substring(0, cursorCharacter)).toFloat() - 1f, + y = dockPadding.top + cursorLine * (font.lineHeight + 2f), color = cursorColor ) } @@ -1092,7 +1111,7 @@ open class TextInputPanel( text = cursorLine.toString(), align = TextAlign.TOP_RIGHT, x = width, - y = 0f, + y = dockPadding.top, color = cursorColor ) @@ -1101,8 +1120,8 @@ open class TextInputPanel( buffer = BUFFER, text = cursorCharacter.toString(), align = TextAlign.TOP_RIGHT, - x = width, - y = font.lineHeight + 2f, + x = width - dockPadding.right, + y = dockPadding.top + font.lineHeight + 2f, color = cursorColor ) @@ -1111,8 +1130,8 @@ open class TextInputPanel( buffer = BUFFER, text = lines.size.toString(), align = TextAlign.TOP_RIGHT, - x = width, - y = font.lineHeight * 2 + 4f, + x = width - dockPadding.right, + y = dockPadding.top + font.lineHeight * 2 + 4f, color = cursorColor ) } @@ -1142,10 +1161,20 @@ open class TextInputPanel( return true } + @Suppress("name_shadowing") fun localToText(x: Float, y: Float): Vector2i { if (lines.isEmpty()) return Vector2i(0, 0) + var x = x - dockPadding.left + var y = y - dockPadding.top + + if (y > height - dockPadding.bottom) + y = height - dockPadding.bottom + + if (x > width - dockPadding.right) + x = width - dockPadding.right + val line = (y / (font.lineHeight + 2f)).toInt().coerceIn(0, lines.size - 1) val sLine = this[line] ?: return Vector2i(0, line) @@ -1154,29 +1183,6 @@ open class TextInputPanel( else if (x >= font.width(sLine)) return Vector2i(sLine.length, line) - // binary search attempt - // simply: sucks - /*@Suppress("name_shadowing") - var x = x - var start = 0 - var end = sLine.length - 1 - - while (start < end - 1) { - val split = (end - start) / 2 - val before = font.width(sLine.substring(start, start + split)) - - if (x < before) { - end = start + split - } else if (x > before) { - x -= before - start += split - } else { - break - } - } - - return Vector2i(start, line)*/ - val cache = Char2IntOpenHashMap() var accumulatedWidth = 0f diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/RGBAColor.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/RGBAColor.kt index 5aff0aa32..26a611b6b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/RGBAColor.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/RGBAColor.kt @@ -76,33 +76,38 @@ data class RGBAColor(val red: Float, val green: Float, val blue: Float, val alph ) } + val isFullyTransparent get() = alpha <= 0f + companion object { - val BLACK = RGBAColor(0f, 0f, 0f, 1f) - val WHITE = RGBAColor(1f, 1f, 1f, 1f) - val RED = RGBAColor(1f, 0f, 0f) - val GREEN = RGBAColor(0f, 1f, 0f, 1f) - val LIGHT_GREEN = RGBAColor(136, 255, 124) - val SLATE_GRAY = RGBAColor(64, 64, 64) - val GRAY = RGBAColor(0x2C2C2CFFL) + @JvmField val TRANSPARENT_BLACK = RGBAColor(0f, 0f, 0f, 0f) + @JvmField val TRANSPARENT_WHITE = RGBAColor(1f, 1f, 1f, 0f) - val DARK_BLUE = rgb(ChatFormatting.DARK_BLUE.color!!) - val DARK_GREEN = rgb(ChatFormatting.DARK_GREEN.color!!) - val DARK_AQUA = rgb(ChatFormatting.DARK_AQUA.color!!) - val DARK_RED = rgb(ChatFormatting.DARK_RED.color!!) - val DARK_PURPLE = rgb(ChatFormatting.DARK_PURPLE.color!!) - val GOLD = rgb(ChatFormatting.GOLD.color!!) - val DARK_GRAY = rgb(ChatFormatting.DARK_GRAY.color!!) - val BLUE = rgb(ChatFormatting.BLUE.color!!) - val AQUA = rgb(ChatFormatting.AQUA.color!!) - val LIGHT_PURPLE = rgb(ChatFormatting.LIGHT_PURPLE.color!!) - val YELLOW = rgb(ChatFormatting.YELLOW.color!!) + @JvmField val BLACK = RGBAColor(0f, 0f, 0f, 1f) + @JvmField val WHITE = RGBAColor(1f, 1f, 1f, 1f) + @JvmField val RED = RGBAColor(1f, 0f, 0f) + @JvmField val GREEN = RGBAColor(0f, 1f, 0f, 1f) + @JvmField val LIGHT_GREEN = RGBAColor(136, 255, 124) + @JvmField val SLATE_GRAY = RGBAColor(64, 64, 64) + @JvmField val GRAY = RGBAColor(0x2C2C2CFFL) - val LOW_POWER = RGBAColor(173, 41, 41) - val FULL_POWER = RGBAColor(255, 242, 40) - val LOW_MATTER = RGBAColor(0, 24, 148) - val FULL_MATTER = RGBAColor(72, 90, 255) - val LOW_PATTERNS = RGBAColor(44, 104, 57) - val FULL_PATTERNS = RGBAColor(65, 255, 87) + @JvmField val DARK_BLUE = rgb(ChatFormatting.DARK_BLUE.color!!) + @JvmField val DARK_GREEN = rgb(ChatFormatting.DARK_GREEN.color!!) + @JvmField val DARK_AQUA = rgb(ChatFormatting.DARK_AQUA.color!!) + @JvmField val DARK_RED = rgb(ChatFormatting.DARK_RED.color!!) + @JvmField val DARK_PURPLE = rgb(ChatFormatting.DARK_PURPLE.color!!) + @JvmField val GOLD = rgb(ChatFormatting.GOLD.color!!) + @JvmField val DARK_GRAY = rgb(ChatFormatting.DARK_GRAY.color!!) + @JvmField val BLUE = rgb(ChatFormatting.BLUE.color!!) + @JvmField val AQUA = rgb(ChatFormatting.AQUA.color!!) + @JvmField val LIGHT_PURPLE = rgb(ChatFormatting.LIGHT_PURPLE.color!!) + @JvmField val YELLOW = rgb(ChatFormatting.YELLOW.color!!) + + @JvmField val LOW_POWER = RGBAColor(173, 41, 41) + @JvmField val FULL_POWER = RGBAColor(255, 242, 40) + @JvmField val LOW_MATTER = RGBAColor(0, 24, 148) + @JvmField val FULL_MATTER = RGBAColor(72, 90, 255) + @JvmField val LOW_PATTERNS = RGBAColor(44, 104, 57) + @JvmField val FULL_PATTERNS = RGBAColor(65, 255, 87) fun inv(color: Int): RGBAColor { val r = (color and -0x1000000 ushr 24) / 255f