acceptsCharacter, support text padding in text input

This commit is contained in:
DBotThePony 2023-01-27 11:39:02 +07:00
parent 03927bfc72
commit f76fe4add6
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 72 additions and 61 deletions

View File

@ -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.drawAligned
import ru.dbotthepony.mc.otm.client.render.drawRect import ru.dbotthepony.mc.otm.client.render.drawRect
import ru.dbotthepony.mc.otm.client.render.tesselator 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.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
@ -144,6 +145,11 @@ open class TextInputPanel<out S : Screen>(
open var backgroundColor = RGBAColor.BLACK open var backgroundColor = RGBAColor.BLACK
open var isActive = true open var isActive = true
init {
scissor = true
dockPadding = DockProperty(2f, 2f, 2f, 2f)
}
private var oldText = ArrayList<String>() private var oldText = ArrayList<String>()
private var textCache: String? = null private var textCache: String? = null
private val lines = ArrayList<String>() private val lines = ArrayList<String>()
@ -968,12 +974,21 @@ open class TextInputPanel<out S : Screen>(
return true return true
} }
open fun acceptsCharacter(codepoint: Char, mods: Int = 0): Boolean {
return true
}
override fun charTypedInternal(codepoint: Char, mods: Int): Boolean { override fun charTypedInternal(codepoint: Char, mods: Int): Boolean {
if (!isActive) { if (!isActive) {
killFocus() killFocus()
return true return true
} }
if (!acceptsCharacter(codepoint, mods)) {
playGuiClickSound()
return true
}
wipeSelection() wipeSelection()
if (!multiLine) if (!multiLine)
@ -1003,9 +1018,10 @@ open class TextInputPanel<out S : Screen>(
} }
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) { override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
if (!backgroundColor.isFullyTransparent)
drawRect(stack, 0f, 0f, width, height, backgroundColor) drawRect(stack, 0f, 0f, width, height, backgroundColor)
var y = 0f var y = dockPadding.top
for ((i, line) in lines.withIndex()) { for ((i, line) in lines.withIndex()) {
val selection = selections[i] val selection = selections[i]
@ -1015,7 +1031,7 @@ open class TextInputPanel<out S : Screen>(
buffer = BUFFER, buffer = BUFFER,
text = line, text = line,
align = TextAlign.TOP_LEFT, align = TextAlign.TOP_LEFT,
x = 0f, x = dockPadding.left,
y = y, y = y,
color = textColor color = textColor
) )
@ -1023,10 +1039,10 @@ open class TextInputPanel<out S : Screen>(
if (selection != null && selection.isValid) { if (selection != null && selection.isValid) {
val (before, selected) = selection.sub(line) val (before, selected) = selection.sub(line)
var x = 0f var x = dockPadding.left
if (before.isNotEmpty()) { 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() 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<out S : Screen>(
} }
y += font.lineHeight + 2f y += font.lineHeight + 2f
if (y > height - dockPadding.bottom)
break
} }
if (isFocused && milliTime % 1000L > 500L) { if (isFocused && milliTime % 1000L > 500L) {
@ -1068,8 +1087,8 @@ open class TextInputPanel<out S : Screen>(
buffer = BUFFER, buffer = BUFFER,
text = "_", text = "_",
align = TextAlign.TOP_LEFT, align = TextAlign.TOP_LEFT,
x = if (activeLine == null) 0f else font.width(activeLine).toFloat(), x = dockPadding.left + (if (activeLine == null) 0f else font.width(activeLine).toFloat()),
y = cursorLine * (font.lineHeight + 2f), y = dockPadding.top + cursorLine * (font.lineHeight + 2f),
color = cursorColor color = cursorColor
) )
} else { } else {
@ -1078,8 +1097,8 @@ open class TextInputPanel<out S : Screen>(
buffer = BUFFER, buffer = BUFFER,
text = "|", text = "|",
align = TextAlign.TOP_LEFT, align = TextAlign.TOP_LEFT,
x = font.width(activeLine.substring(0, cursorCharacter)).toFloat() - 1f, x = dockPadding.left + font.width(activeLine.substring(0, cursorCharacter)).toFloat() - 1f,
y = cursorLine * (font.lineHeight + 2f), y = dockPadding.top + cursorLine * (font.lineHeight + 2f),
color = cursorColor color = cursorColor
) )
} }
@ -1092,7 +1111,7 @@ open class TextInputPanel<out S : Screen>(
text = cursorLine.toString(), text = cursorLine.toString(),
align = TextAlign.TOP_RIGHT, align = TextAlign.TOP_RIGHT,
x = width, x = width,
y = 0f, y = dockPadding.top,
color = cursorColor color = cursorColor
) )
@ -1101,8 +1120,8 @@ open class TextInputPanel<out S : Screen>(
buffer = BUFFER, buffer = BUFFER,
text = cursorCharacter.toString(), text = cursorCharacter.toString(),
align = TextAlign.TOP_RIGHT, align = TextAlign.TOP_RIGHT,
x = width, x = width - dockPadding.right,
y = font.lineHeight + 2f, y = dockPadding.top + font.lineHeight + 2f,
color = cursorColor color = cursorColor
) )
@ -1111,8 +1130,8 @@ open class TextInputPanel<out S : Screen>(
buffer = BUFFER, buffer = BUFFER,
text = lines.size.toString(), text = lines.size.toString(),
align = TextAlign.TOP_RIGHT, align = TextAlign.TOP_RIGHT,
x = width, x = width - dockPadding.right,
y = font.lineHeight * 2 + 4f, y = dockPadding.top + font.lineHeight * 2 + 4f,
color = cursorColor color = cursorColor
) )
} }
@ -1142,10 +1161,20 @@ open class TextInputPanel<out S : Screen>(
return true return true
} }
@Suppress("name_shadowing")
fun localToText(x: Float, y: Float): Vector2i { fun localToText(x: Float, y: Float): Vector2i {
if (lines.isEmpty()) if (lines.isEmpty())
return Vector2i(0, 0) 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 line = (y / (font.lineHeight + 2f)).toInt().coerceIn(0, lines.size - 1)
val sLine = this[line] ?: return Vector2i(0, line) val sLine = this[line] ?: return Vector2i(0, line)
@ -1154,29 +1183,6 @@ open class TextInputPanel<out S : Screen>(
else if (x >= font.width(sLine)) else if (x >= font.width(sLine))
return Vector2i(sLine.length, line) 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() val cache = Char2IntOpenHashMap()
var accumulatedWidth = 0f var accumulatedWidth = 0f

View File

@ -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 { companion object {
val BLACK = RGBAColor(0f, 0f, 0f, 1f) @JvmField val TRANSPARENT_BLACK = RGBAColor(0f, 0f, 0f, 0f)
val WHITE = RGBAColor(1f, 1f, 1f, 1f) @JvmField val TRANSPARENT_WHITE = RGBAColor(1f, 1f, 1f, 0f)
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)
val DARK_BLUE = rgb(ChatFormatting.DARK_BLUE.color!!) @JvmField val BLACK = RGBAColor(0f, 0f, 0f, 1f)
val DARK_GREEN = rgb(ChatFormatting.DARK_GREEN.color!!) @JvmField val WHITE = RGBAColor(1f, 1f, 1f, 1f)
val DARK_AQUA = rgb(ChatFormatting.DARK_AQUA.color!!) @JvmField val RED = RGBAColor(1f, 0f, 0f)
val DARK_RED = rgb(ChatFormatting.DARK_RED.color!!) @JvmField val GREEN = RGBAColor(0f, 1f, 0f, 1f)
val DARK_PURPLE = rgb(ChatFormatting.DARK_PURPLE.color!!) @JvmField val LIGHT_GREEN = RGBAColor(136, 255, 124)
val GOLD = rgb(ChatFormatting.GOLD.color!!) @JvmField val SLATE_GRAY = RGBAColor(64, 64, 64)
val DARK_GRAY = rgb(ChatFormatting.DARK_GRAY.color!!) @JvmField val GRAY = RGBAColor(0x2C2C2CFFL)
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!!)
val LOW_POWER = RGBAColor(173, 41, 41) @JvmField val DARK_BLUE = rgb(ChatFormatting.DARK_BLUE.color!!)
val FULL_POWER = RGBAColor(255, 242, 40) @JvmField val DARK_GREEN = rgb(ChatFormatting.DARK_GREEN.color!!)
val LOW_MATTER = RGBAColor(0, 24, 148) @JvmField val DARK_AQUA = rgb(ChatFormatting.DARK_AQUA.color!!)
val FULL_MATTER = RGBAColor(72, 90, 255) @JvmField val DARK_RED = rgb(ChatFormatting.DARK_RED.color!!)
val LOW_PATTERNS = RGBAColor(44, 104, 57) @JvmField val DARK_PURPLE = rgb(ChatFormatting.DARK_PURPLE.color!!)
val FULL_PATTERNS = RGBAColor(65, 255, 87) @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 { fun inv(color: Int): RGBAColor {
val r = (color and -0x1000000 ushr 24) / 255f val r = (color and -0x1000000 ushr 24) / 255f