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.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<out S : Screen>(
open var backgroundColor = RGBAColor.BLACK
open var isActive = true
init {
scissor = true
dockPadding = DockProperty(2f, 2f, 2f, 2f)
}
private var oldText = ArrayList<String>()
private var textCache: String? = null
private val lines = ArrayList<String>()
@ -968,12 +974,21 @@ open class TextInputPanel<out S : Screen>(
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<out S : Screen>(
}
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<out S : Screen>(
buffer = BUFFER,
text = line,
align = TextAlign.TOP_LEFT,
x = 0f,
x = dockPadding.left,
y = y,
color = textColor
)
@ -1023,10 +1039,10 @@ open class TextInputPanel<out S : Screen>(
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<out S : Screen>(
}
y += font.lineHeight + 2f
if (y > height - dockPadding.bottom)
break
}
if (isFocused && milliTime % 1000L > 500L) {
@ -1068,8 +1087,8 @@ open class TextInputPanel<out S : Screen>(
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<out S : Screen>(
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<out S : Screen>(
text = cursorLine.toString(),
align = TextAlign.TOP_RIGHT,
x = width,
y = 0f,
y = dockPadding.top,
color = cursorColor
)
@ -1101,8 +1120,8 @@ open class TextInputPanel<out S : Screen>(
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<out S : Screen>(
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<out S : Screen>(
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<out S : Screen>(
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

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 {
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