mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-19 04:15:14 -04:00
gui: text marking
This commit is contained in:
parent
c587451f22
commit
9eadbe5da6
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2022 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.gui.elements.text.mark
|
||||
|
||||
import de.bixilon.minosoft.config.key.KeyCodes
|
||||
import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.data.text.RGBColor
|
||||
import de.bixilon.minosoft.gui.rendering.RenderConstants
|
||||
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
|
||||
import de.bixilon.minosoft.gui.rendering.gui.input.ModifierKeys
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
|
||||
import glm_.vec2.Vec2i
|
||||
|
||||
class MarkTextElement(
|
||||
guiRenderer: GUIRenderer,
|
||||
text: Any,
|
||||
fontAlignment: HorizontalAlignments = HorizontalAlignments.LEFT,
|
||||
background: Boolean = true,
|
||||
backgroundColor: RGBColor = RenderConstants.TEXT_BACKGROUND_COLOR,
|
||||
noBorder: Boolean = false,
|
||||
parent: Element? = null,
|
||||
scale: Float = 1.0f,
|
||||
) : TextElement(guiRenderer, text, fontAlignment, background, backgroundColor, noBorder, parent, scale) {
|
||||
var markStartPosition = 0
|
||||
var markEndPosition = 0
|
||||
|
||||
val marked: Boolean
|
||||
get() = markStartPosition >= 0
|
||||
|
||||
val markedText: String
|
||||
get() {
|
||||
if (!marked) {
|
||||
return ""
|
||||
}
|
||||
return chatComponent.message.substring(markStartPosition, markEndPosition)
|
||||
}
|
||||
|
||||
override var chatComponent: ChatComponent
|
||||
get() = super.chatComponent
|
||||
set(value) {
|
||||
super.chatComponent = value
|
||||
unmark()
|
||||
}
|
||||
|
||||
fun mark(start: Int, end: Int) {
|
||||
markStartPosition = start
|
||||
markEndPosition = end
|
||||
forceSilentApply()
|
||||
}
|
||||
|
||||
fun unmark() {
|
||||
if (!marked) {
|
||||
return
|
||||
}
|
||||
markStartPosition = -1
|
||||
markEndPosition = -1
|
||||
forceSilentApply()
|
||||
}
|
||||
|
||||
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
||||
|
||||
if (markStartPosition >= 0) {
|
||||
for (line in renderInfo.lines) {
|
||||
// ToDo
|
||||
}
|
||||
}
|
||||
|
||||
return super.forceRender(offset, z, consumer, options) + 1
|
||||
}
|
||||
|
||||
override fun onKey(key: KeyCodes, type: KeyChangeTypes) {
|
||||
super.onKey(key, type)
|
||||
|
||||
val controlDown = guiRenderer.isKeyDown(ModifierKeys.CONTROL)
|
||||
|
||||
when (key) {
|
||||
KeyCodes.KEY_A -> {
|
||||
if (!controlDown) {
|
||||
return
|
||||
}
|
||||
mark(0, chatComponent.message.length)
|
||||
}
|
||||
KeyCodes.KEY_ESCAPE -> unmark()
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2022 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.gui.rendering.gui.elements.text.mark
|
||||
|
||||
enum class TextCursorStyles {
|
||||
/**
|
||||
* The cursor is always hidden
|
||||
*/
|
||||
DISABLED,
|
||||
|
||||
/**
|
||||
* Cursor is only visible when text is marked
|
||||
*/
|
||||
MARKED,
|
||||
|
||||
/**
|
||||
* Cursor is visible when something is marked, or you clicked in
|
||||
*/
|
||||
CLICKED,
|
||||
|
||||
/**
|
||||
* Cursor is always visible
|
||||
*/
|
||||
ALWAYS,
|
||||
}
|
@ -20,6 +20,8 @@ import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.text.mark.MarkTextElement
|
||||
import de.bixilon.minosoft.gui.rendering.gui.elements.text.mark.TextCursorStyles
|
||||
import de.bixilon.minosoft.gui.rendering.gui.input.ModifierKeys
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
|
||||
@ -30,33 +32,36 @@ import glm_.vec2.Vec2i
|
||||
class TextInputElement(
|
||||
guiRenderer: GUIRenderer,
|
||||
val maxLength: Int = Int.MAX_VALUE,
|
||||
val cursorStyles: TextCursorStyles = TextCursorStyles.CLICKED,
|
||||
) : Element(guiRenderer) {
|
||||
private val cursor = ColorElement(guiRenderer, size = Vec2i(1, Font.TOTAL_CHAR_HEIGHT))
|
||||
private val textElement = TextElement(guiRenderer, "", background = false, parent = this)
|
||||
private val textElement = MarkTextElement(guiRenderer, "", background = false, parent = this)
|
||||
private val background = ColorElement(guiRenderer, Vec2i.EMPTY, RenderConstants.TEXT_BACKGROUND_COLOR)
|
||||
private var cursorOffset: Vec2i = Vec2i.EMPTY
|
||||
private var _value: String = ""
|
||||
private val _value = StringBuffer(256)
|
||||
var value: String
|
||||
get() = _value
|
||||
get() = _value.toString()
|
||||
set(value) {
|
||||
pointer = 0
|
||||
if (_value == value) {
|
||||
if (_value.equals(value)) {
|
||||
return
|
||||
}
|
||||
_value = value
|
||||
_value.replace(0, _value.length, value)
|
||||
forceApply()
|
||||
}
|
||||
private var pointer = 0
|
||||
private var cursorTick = 0
|
||||
|
||||
|
||||
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
|
||||
background.render(offset, z, consumer, options)
|
||||
textElement.render(offset, z + 1, consumer, options)
|
||||
var zOffset = background.render(offset, z, consumer, options)
|
||||
|
||||
zOffset += textElement.render(offset, z + zOffset, consumer, options)
|
||||
|
||||
if (cursorTick < 20) {
|
||||
cursor.render(offset + cursorOffset, z + 1 + TextElement.LAYERS, consumer, options)
|
||||
cursor.render(offset + cursorOffset, z + zOffset, consumer, options)
|
||||
}
|
||||
return TextElement.LAYERS + 2
|
||||
return zOffset + 1
|
||||
}
|
||||
|
||||
override fun forceSilentApply() {
|
||||
@ -84,9 +89,13 @@ class TextInputElement(
|
||||
cacheUpToDate = false
|
||||
}
|
||||
|
||||
private fun silentAppend(string: String) {
|
||||
val appendLength = minOf(string.length, maxLength - _value.length)
|
||||
_value = _value.substring(0, pointer) + string.substring(0, appendLength) + _value.substring(pointer, _value.length)
|
||||
private fun insert(string: String) {
|
||||
val insert = string.replace("\n", "").replace("\r", "").replace('§', '&')
|
||||
if (textElement.markStartPosition > 0) {
|
||||
_value.delete(textElement.markStartPosition, textElement.markEndPosition)
|
||||
}
|
||||
val appendLength = minOf(insert.length, maxLength - _value.length)
|
||||
_value.insert(pointer, insert.substring(0, appendLength))
|
||||
pointer += appendLength
|
||||
}
|
||||
|
||||
@ -95,48 +104,83 @@ class TextInputElement(
|
||||
return
|
||||
}
|
||||
cursorTick = CURSOR_TICK_ON_ACTION
|
||||
silentAppend(char.toChar().toString())
|
||||
insert(char.toChar().toString())
|
||||
forceApply()
|
||||
}
|
||||
|
||||
private fun mark(mark: Boolean, right: Boolean) {
|
||||
if (mark) {
|
||||
var start: Int = textElement.markStartPosition
|
||||
var end: Int = textElement.markEndPosition
|
||||
if (right) {
|
||||
if (start < 0) {
|
||||
start = pointer
|
||||
end = start
|
||||
}
|
||||
end++
|
||||
} else {
|
||||
if (start < 0) {
|
||||
end = pointer
|
||||
start = end
|
||||
}
|
||||
start--
|
||||
}
|
||||
textElement.mark(start, end)
|
||||
} else {
|
||||
textElement.unmark()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onKey(key: KeyCodes, type: KeyChangeTypes) {
|
||||
if (type == KeyChangeTypes.RELEASE) {
|
||||
return
|
||||
}
|
||||
val controlDown = guiRenderer.isKeyDown(ModifierKeys.CONTROL)
|
||||
val shiftDown = guiRenderer.isKeyDown(ModifierKeys.SHIFT)
|
||||
cursorTick = CURSOR_TICK_ON_ACTION
|
||||
when (key) {
|
||||
KeyCodes.KEY_V -> {
|
||||
if (controlDown) {
|
||||
silentAppend(guiRenderer.renderWindow.window.clipboardText)
|
||||
insert(guiRenderer.renderWindow.window.clipboardText)
|
||||
}
|
||||
}
|
||||
KeyCodes.KEY_C -> {
|
||||
if (controlDown) {
|
||||
val markedText = textElement.markedText
|
||||
if (markedText.isEmpty()) {
|
||||
return
|
||||
}
|
||||
renderWindow.window.clipboardText = markedText
|
||||
}
|
||||
}
|
||||
KeyCodes.KEY_BACKSPACE -> {
|
||||
if (pointer == 0 || _value.isEmpty()) {
|
||||
return
|
||||
}
|
||||
_value = _value.removeRange(pointer - 1, pointer)
|
||||
_value.deleteCharAt(pointer - 1)
|
||||
pointer--
|
||||
}
|
||||
KeyCodes.KEY_DELETE -> {
|
||||
if (pointer == _value.length || _value.isEmpty()) {
|
||||
return
|
||||
}
|
||||
_value = _value.removeRange(pointer, pointer + 1)
|
||||
_value.deleteCharAt(pointer)
|
||||
}
|
||||
KeyCodes.KEY_LEFT -> {
|
||||
if (pointer == 0) {
|
||||
return
|
||||
}
|
||||
mark(shiftDown, false)
|
||||
pointer--
|
||||
}
|
||||
KeyCodes.KEY_RIGHT -> {
|
||||
if (pointer == _value.length) {
|
||||
return
|
||||
}
|
||||
mark(shiftDown, true)
|
||||
pointer++
|
||||
}
|
||||
else -> return
|
||||
else -> return textElement.onKey(key, type)
|
||||
}
|
||||
forceApply()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user