diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/TextInputPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/TextInputPanel.kt index 668abe3ba..d50effbf4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/TextInputPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/TextInputPanel.kt @@ -34,6 +34,7 @@ open class TextInputPanel( private data class TextSelection(val start: Int, val end: Int) { val isInversed get() = start > end val isNotEmpty get() = start != end + val isValid get() = start != end val actualStart get() = if (isInversed) this.end else this.start val actualEnd get() = if (isInversed) this.start else this.end @@ -67,6 +68,14 @@ open class TextInputPanel( } } + private fun putSelection(index: Int, selection: TextSelection) { + if (selection.isValid) { + selections[index] = selection + } else { + selections.remove(index) + } + } + private inner class Snapshot { private val lines = ArrayList(this@TextInputPanel.lines) // ultra fast copy private val cursorLine = this@TextInputPanel.cursorLine @@ -296,19 +305,19 @@ open class TextInputPanel( val (start, end) = selection if (character < start) { - selections[line] = TextSelection(start + moveBy, end + moveBy) + putSelection(line, TextSelection(start + moveBy, end + moveBy)) } else if (character > end && character + moveBy < end) { if (character + moveBy < start) { // selections.remove(line) selections[line] = TextSelection(0, 0) } else { - selections[line] = TextSelection(start, character + moveBy) + putSelection(line, TextSelection(start, character + moveBy)) } } else if (character in start .. end) { if (moveBy > 0 || character + moveBy <= start) { - selections[line] = TextSelection(start, end + moveBy) + putSelection(line, TextSelection(start, end + moveBy)) } else { - selections[line] = TextSelection(character + moveBy, end + moveBy) + putSelection(line, TextSelection(character + moveBy, end + moveBy)) } } } @@ -319,29 +328,41 @@ open class TextInputPanel( return pushbackSnapshotIfNoTimer() + val set = selections.int2ObjectEntrySet() - val inversed = ArrayList(selections.int2ObjectEntrySet()) + while (set.isNotEmpty()) { + val (lineNumber, selection) = set.last() + selections.remove(lineNumber) + val line = this[lineNumber] ?: continue + if (!selection.isValid) continue // ??? - var downTo = inversed.size.ushr(1) - if (inversed.size and 1 == 1) downTo++ - - for (i in inversed.size - 1 downTo downTo) { - val i2 = inversed.size - i - val a = inversed[i] - val b = inversed[i2] - inversed[i] = b - inversed[i2] = a - } - - for ((lineNumber, selection) in inversed) { - if (selection.start != selection.end) { - if (selection.start == 0 && selection.end == this[lineNumber]!!.length) { + if (selection.coversEntireLine(line)) { + removeLine(lineNumber) + } else if (selection.coversEntireString(line)) { + this[lineNumber] = "" + } else if (selection.coversNewline(line)) { + val before = line.substring(0, selection.actualStart.coerceIn(0, line.length)) + val next = this[lineNumber + 1] + if (next == null) { + this[lineNumber] = before + } else { + this[lineNumber] = before + next + removeLine(lineNumber + 1) } + } else { + val before = line.substring(0, selection.actualStart.coerceIn(0, line.length)) + val after = line.substring(selection.actualEnd.coerceIn(0, line.length)) + this[lineNumber] = before + after + } + + if (lineNumber < cursorLine) { + cursorLine = lineNumber + cursorCharacter = selection.actualStart + } else if (lineNumber == cursorLine && cursorCharacter > selection.actualStart) { + cursorCharacter = selection.actualStart } } - - // selections.clear() } protected open fun textChanged(oldText: String, newText: String) {} @@ -453,22 +474,22 @@ open class TextInputPanel( val result = advanceCursorLeft(greedy) if (!result.linesChanged) - selections[result.oldLine] = TextSelection( + putSelection(result.oldLine, TextSelection( existing?.start ?: result.oldCharacter, - result.newCharacter) + result.newCharacter)) else { this[result.newLine]?.let { val existingNewline = selections[result.newLine] if (existingNewline == null) { - selections[result.newLine] = TextSelection( + putSelection(result.newLine, TextSelection( Int.MAX_VALUE, - it.length) + it.length)) } else { if (!existingNewline.isInversed) { - selections[result.newLine] = TextSelection( + putSelection(result.newLine, TextSelection( existingNewline.start, - result.newCharacter) + result.newCharacter)) } } } @@ -485,9 +506,9 @@ open class TextInputPanel( val existing = selections[cursorLine] val result = advanceCursorRight(greedy) - selections[result.oldLine] = TextSelection( + putSelection(result.oldLine, TextSelection( existing?.start ?: result.oldCharacter, - if (result.couldHaveChangedLine) Int.MAX_VALUE else result.newCharacter) + if (result.couldHaveChangedLine) Int.MAX_VALUE else result.newCharacter)) } override fun keyPressedInternal(key: Int, scancode: Int, mods: Int): Boolean { @@ -644,7 +665,10 @@ open class TextInputPanel( } if (key == InputConstants.KEY_BACKSPACE) { - wipeSelection() + if (selections.isNotEmpty()) { + wipeSelection() + return true + } val line = this[cursorLine] @@ -692,7 +716,10 @@ open class TextInputPanel( } if (key == InputConstants.KEY_DELETE) { - wipeSelection() + if (selections.isNotEmpty()) { + wipeSelection() + return true + } if (cursorLine !in 0 until lines.size) { cursorLine = lines.size - 1 @@ -799,7 +826,7 @@ open class TextInputPanel( color = textColor ) - if (selection != null && (selection.isNotEmpty || selection.coversEntireLine(line))) { + if (selection != null && selection.isValid && (selection.isNotEmpty || selection.coversEntireLine(line))) { val (before, selected) = selection.sub(line) var x = 0f