Line and row scrolling
This commit is contained in:
parent
fd84c40c1e
commit
64a54add95
@ -27,6 +27,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.core.addAll
|
||||
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
||||
import ru.dbotthepony.mc.otm.milliTime
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
open class TextInputPanel<out S : Screen>(
|
||||
screen: S,
|
||||
@ -158,6 +159,18 @@ open class TextInputPanel<out S : Screen>(
|
||||
private val undo = ArrayDeque<Snapshot>()
|
||||
private val redo = ArrayDeque<Snapshot>()
|
||||
|
||||
/**
|
||||
* scroll in rows (up-down)
|
||||
*/
|
||||
private var scrollLines = 0
|
||||
|
||||
/**
|
||||
* scroll in pixels (left-right)
|
||||
*/
|
||||
private var scrollPixels = 0f
|
||||
|
||||
var rowSpacing = 2f
|
||||
|
||||
private fun triggerChangeCallback() {
|
||||
if (oldText != lines) {
|
||||
textCache = null
|
||||
@ -1018,13 +1031,59 @@ open class TextInputPanel<out S : Screen>(
|
||||
return true
|
||||
}
|
||||
|
||||
private val characterWidthCache = Char2IntOpenHashMap()
|
||||
|
||||
private fun width(char: Char): Int {
|
||||
return characterWidthCache.computeIfAbsent(char, Char2IntFunction { font.width(it.toString()) })
|
||||
}
|
||||
|
||||
private fun width(text: String, beginning: Int = 0, end: Int = text.length - 1): Int {
|
||||
var accumulate = 0
|
||||
|
||||
for (i in beginning.coerceAtLeast(0) .. end.coerceAtMost(text.length - 1)) {
|
||||
accumulate += width(text[i])
|
||||
}
|
||||
|
||||
return accumulate
|
||||
}
|
||||
|
||||
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
if (!backgroundColor.isFullyTransparent)
|
||||
drawRect(stack, 0f, 0f, width, height, backgroundColor)
|
||||
|
||||
if (multiLine) {
|
||||
val heightInLines = ((height - dockPadding.top - dockPadding.bottom) / (font.lineHeight + rowSpacing)).toInt()
|
||||
|
||||
if (heightInLines > 0) {
|
||||
if (cursorLine < scrollLines) {
|
||||
scrollLines = (cursorLine - 1).coerceAtLeast(0)
|
||||
} else if (heightInLines + scrollLines < cursorLine) {
|
||||
scrollLines = (cursorLine - heightInLines).coerceIn(0, lines.size - 2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scrollLines = 0
|
||||
}
|
||||
|
||||
val selectedLine = this[cursorLine]
|
||||
|
||||
if (selectedLine != null) {
|
||||
val w = width(selectedLine, end = cursorRow) - scrollPixels
|
||||
|
||||
if (w < 0f) {
|
||||
scrollPixels = (scrollPixels - 30f).coerceAtLeast(0f)
|
||||
} else if (w >= width - dockPadding.right) {
|
||||
scrollPixels += 30f
|
||||
}
|
||||
}
|
||||
|
||||
stack.pushPose()
|
||||
stack.translate(-scrollPixels, 0f, 0f)
|
||||
|
||||
var y = dockPadding.top
|
||||
|
||||
for ((i, line) in lines.withIndex()) {
|
||||
for (i in scrollLines until lines.size) {
|
||||
val line = lines[i]
|
||||
val selection = selections[i]
|
||||
|
||||
font.drawAligned(
|
||||
@ -1046,7 +1105,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
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 + scrollPixels else font.width(selected).toFloat()
|
||||
|
||||
RenderSystem.setShader(GameRenderer::getPositionShader)
|
||||
RenderSystem.setShaderColor(cursorColor.red, cursorColor.green, cursorColor.blue, 0.4f)
|
||||
@ -1060,8 +1119,8 @@ open class TextInputPanel<out S : Screen>(
|
||||
|
||||
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION)
|
||||
|
||||
builder.vertex(stack.last().pose(), x, y + font.lineHeight + 2f, 0f).endVertex()
|
||||
builder.vertex(stack.last().pose(), x + width, y + font.lineHeight + 2f, 0f).endVertex()
|
||||
builder.vertex(stack.last().pose(), x, y + font.lineHeight + rowSpacing, 0f).endVertex()
|
||||
builder.vertex(stack.last().pose(), x + width, y + font.lineHeight + rowSpacing, 0f).endVertex()
|
||||
builder.vertex(stack.last().pose(), x + width, y, 0f).endVertex()
|
||||
builder.vertex(stack.last().pose(), x, y, 0f).endVertex()
|
||||
|
||||
@ -1073,7 +1132,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
RenderSystem.enableDepthTest()
|
||||
}
|
||||
|
||||
y += font.lineHeight + 2f
|
||||
y += font.lineHeight + rowSpacing
|
||||
|
||||
if (y > height - dockPadding.bottom)
|
||||
break
|
||||
@ -1089,7 +1148,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
text = "_",
|
||||
align = TextAlign.TOP_LEFT,
|
||||
x = dockPadding.left + (if (activeLine == null) 0f else font.width(activeLine).toFloat()),
|
||||
y = dockPadding.top + cursorLine * (font.lineHeight + 2f),
|
||||
y = dockPadding.top + (cursorLine - scrollLines) * (font.lineHeight + rowSpacing),
|
||||
color = cursorColor
|
||||
)
|
||||
} else {
|
||||
@ -1099,12 +1158,14 @@ open class TextInputPanel<out S : Screen>(
|
||||
text = "|",
|
||||
align = TextAlign.TOP_LEFT,
|
||||
x = dockPadding.left + font.width(activeLine.substring(0, cursorRow)).toFloat() - 1f,
|
||||
y = dockPadding.top + cursorLine * (font.lineHeight + 2f),
|
||||
y = dockPadding.top + (cursorLine - scrollLines) * (font.lineHeight + rowSpacing),
|
||||
color = cursorColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
stack.popPose()
|
||||
|
||||
if (debugDraw) {
|
||||
font.drawAligned(
|
||||
poseStack = stack,
|
||||
@ -1122,7 +1183,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
text = cursorRow.toString(),
|
||||
align = TextAlign.TOP_RIGHT,
|
||||
x = width - dockPadding.right,
|
||||
y = dockPadding.top + font.lineHeight + 2f,
|
||||
y = dockPadding.top + font.lineHeight + rowSpacing,
|
||||
color = cursorColor
|
||||
)
|
||||
|
||||
@ -1132,7 +1193,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
text = lines.size.toString(),
|
||||
align = TextAlign.TOP_RIGHT,
|
||||
x = width - dockPadding.right,
|
||||
y = dockPadding.top + font.lineHeight * 2 + 4f,
|
||||
y = dockPadding.top + font.lineHeight * 2f + rowSpacing * 2f,
|
||||
color = cursorColor
|
||||
)
|
||||
}
|
||||
@ -1181,19 +1242,20 @@ open class TextInputPanel<out S : Screen>(
|
||||
if (x > width - dockPadding.right)
|
||||
x = width - dockPadding.right
|
||||
|
||||
val line = (y / (font.lineHeight + 2f)).toInt().coerceIn(0, lines.size - 1)
|
||||
x += scrollPixels
|
||||
|
||||
val line = (scrollLines + (y / (font.lineHeight + rowSpacing)).toInt()).coerceIn(0, lines.size - 1)
|
||||
val sLine = this[line] ?: return Vector2i(0, line)
|
||||
|
||||
if (x <= 0f)
|
||||
return Vector2i(0, line)
|
||||
else if (x >= font.width(sLine))
|
||||
else if (x >= width(sLine))
|
||||
return Vector2i(sLine.length, line)
|
||||
|
||||
val cache = Char2IntOpenHashMap()
|
||||
var accumulatedWidth = 0f
|
||||
|
||||
for ((i, char) in sLine.withIndex()) {
|
||||
val width = cache.computeIfAbsent(char, Char2IntFunction { font.width(it.toString()) })
|
||||
val width = width(char)
|
||||
|
||||
if (x in accumulatedWidth .. accumulatedWidth + width) {
|
||||
if (x - accumulatedWidth < width / 2)
|
||||
|
Loading…
Reference in New Issue
Block a user