Simplify TextInput and fix few small bugs

This commit is contained in:
UnicornFreedom 2025-08-20 18:44:57 +02:00
parent 81840e4fab
commit 841733f6fe
No known key found for this signature in database
GPG Key ID: B4ED0DB6B940024F

View File

@ -52,9 +52,8 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w
def text: String = chars.mkString
def text_=(value: String): Unit = {
chars = value.toCharArray
cursorPos = 0
cursorOffset = 0
textChanged = true
adjustCursor(0)
// note: we are not setting `textChanged = true` here to avoid potential recursion with `onInput` callback
}
protected var placeholder: Array[Char] = "".toCharArray
@ -96,7 +95,7 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w
private def charsWidth(chars: Array[Char], first: Int, last: Int): Int = {
var width = 0
for (index <- first to last) {
for (index <- (first max 0) to (last min (chars.length - 1))) {
width += font().charWidth(chars(index))
}
width
@ -117,53 +116,32 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w
width += charWidth(chars(pos))
if (width < absoluteX) pos += 1
}
cursorPos = chars.length.min(pos).max(0)
cursorOffset = if (cursorPos > 0) charsWidth(chars, 0, (cursorPos - 1).max(0)) else 0
blinkTimer = 0
adjustScroll()
adjustCursor(chars.length.min(pos).max(0))
case event @ KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, Keyboard.KEY_LEFT, _) if isFocused =>
if (cursorPos != 0) {
cursorOffset -= charWidth(chars(cursorPos - 1))
cursorPos -= 1
blinkTimer = 0
adjustScroll()
}
if (cursorPos > 0) adjustCursor(cursorPos - 1)
event.consume()
case event @ KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, Keyboard.KEY_RIGHT, _) if isFocused =>
if (cursorPos < chars.length) {
cursorOffset += charWidth(chars(cursorPos))
cursorPos += 1
blinkTimer = 0
adjustScroll()
}
if (cursorPos < chars.length) adjustCursor(cursorPos + 1)
event.consume()
case event @ KeyEvent(KeyEvent.State.Press, Keyboard.KEY_HOME, _) if isFocused =>
cursorPos = 0
cursorOffset = 0
blinkTimer = 0
scroll = 0
adjustCursor(0)
event.consume()
case event @ KeyEvent(KeyEvent.State.Press, Keyboard.KEY_END, _) if isFocused =>
val textWidth = charsWidth(chars)
cursorPos = chars.length
cursorOffset = textWidth
blinkTimer = 0
scroll = (textWidth - size.width + 16).max(0)
adjustCursor(chars.length)
event.consume()
case event @ KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, Keyboard.KEY_BACK, _) if isFocused =>
val (lhs, rhs) = chars.splitAt(cursorPos)
if (!lhs.isEmpty) {
val cw = charWidth(lhs.last)
chars = lhs.take(lhs.length - 1) ++ rhs
textChanged = true
cursorOffset -= cw
cursorPos -= 1
blinkTimer = 0
adjustCursor(cursorPos - 1)
// if the text overflows - scroll it into visibility, it will feel nicer
val cw = charWidth(lhs.last)
scroll = (scroll - cw).max(0)
}
event.consume()
@ -182,18 +160,12 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w
event.consume()
case event @ KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, Keyboard.KEY_INSERT, _) if isFocused =>
// TODO: insert the whole clipboard string at once instead of going char-by-char.
for (char <- UiHandler.clipboard.toCharArray) {
writeChar(char)
}
writeString(UiHandler.clipboard)
event.consume()
case event @ KeyEvent(KeyEvent.State.Press | KeyEvent.State.Repeat, Keyboard.KEY_V, _)
if isFocused && KeyEvents.isControlDown =>
// TODO: insert the whole clipboard string at once instead of going char-by-char.
for (char <- UiHandler.clipboard.toCharArray) {
writeChar(char)
}
writeString(UiHandler.clipboard)
event.consume()
case event @ KeyEvent(KeyEvent.State.Press, Keyboard.KEY_RETURN, _) if isFocused =>
@ -206,13 +178,26 @@ class TextInput(val initialText: String = "") extends Widget with MouseHandler w
}
private def writeString(string: String): Unit = {
val (lhs, rhs) = chars.splitAt(cursorPos)
val array = string.toCharArray
chars = lhs ++ array ++ rhs
textChanged = true
adjustCursor(cursorPos + string.length)
}
private def writeChar(char: Char): Unit = {
val (lhs, rhs) = chars.splitAt(cursorPos)
chars = lhs ++ Array(char) ++ rhs
textChanged = true
cursorOffset += charWidth(chars(cursorPos))
cursorPos += 1
adjustCursor(cursorPos + 1)
}
private def adjustCursor(position: Int): Unit = {
cursorPos = position
cursorOffset = charsWidth(chars, 0, cursorPos - 1)
blinkTimer = 0
adjustScroll()
}
private def adjustScroll(): Unit = {