text wrapping fixes

This commit is contained in:
Bixilon 2023-06-13 22:10:51 +02:00
parent 8ce641cacf
commit e346f06c67
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
3 changed files with 90 additions and 12 deletions

View File

@ -185,5 +185,72 @@ class ChatComponentRendererTest {
) )
} }
fun `no space x`() {
val info = render(TextComponent("bcd\n\nefgh"), maxSize = Vec2(0.0f, Float.MAX_VALUE))
info.assert(
lineIndex = 0,
lines = listOf(),
size = Vec2(0.0f, 0.0f),
cutOff = true,
)
}
fun `no space y`() {
val info = render(TextComponent("bcd\n\nefgh"), maxSize = Vec2(Float.MAX_VALUE, 0.0f))
info.assert(
lineIndex = 0,
lines = listOf(),
size = Vec2(0.0f, 0.0f),
cutOff = true,
)
}
fun `no space`() {
val info = render(TextComponent("bcd\n\nefgh"), maxSize = Vec2(0.0f, 0.0f))
info.assert(
lineIndex = 0,
lines = listOf(),
size = Vec2(0.0f, 0.0f),
cutOff = true,
)
}
fun `size limit one line`() {
val info = render(TextComponent("bcd\nefgh"), maxSize = Vec2(Float.MAX_VALUE, 11.0f))
info.assert(
lineIndex = 0,
lines = listOf(
TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f),
),
size = Vec2(5.0f, 11.0f),
cutOff = true,
)
}
fun `size limit one line with overflow`() {
val info = render(TextComponent("bcd\nefgh"), maxSize = Vec2(5.0f, 11.0f))
info.assert(
lineIndex = 0,
lines = listOf(
TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f),
),
size = Vec2(5.0f, 11.0f),
cutOff = true,
)
}
fun `size limit two line`() {
val info = render(TextComponent("bcd\nefgh\nabc"), maxSize = Vec2(Float.MAX_VALUE, 22.0f))
info.assert(
lineIndex = 1,
lines = listOf(
TextLineInfo(BaseComponent(TextComponent("bcd")), 5.0f),
TextLineInfo(BaseComponent(TextComponent("efgh")), 14.0f),
),
size = Vec2(14.0f, 22.0f),
cutOff = true,
)
}
// TODO: shadow, cutoff, underline, strikethrough, using with consumer, formatting (just basic, that is code point renderer's job) // TODO: shadow, cutoff, underline, strikethrough, using with consumer, formatting (just basic, that is code point renderer's job)
} }

View File

@ -43,7 +43,7 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
private fun renderNewline(properties: TextRenderProperties, offset: TextOffset, info: TextRenderInfo, updateSize: Boolean): Boolean { private fun renderNewline(properties: TextRenderProperties, offset: TextOffset, info: TextRenderInfo, updateSize: Boolean): Boolean {
val height = offset.getNextLineHeight(properties) val height = offset.getNextLineHeight(properties)
if (!offset.addLine(info, height)) { if (!offset.addLine(info, properties.lineHeight, height)) {
info.cutOff = true info.cutOff = true
return true return true
} }
@ -75,10 +75,13 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
val line = StringBuilder() val line = StringBuilder()
var filled = false var filled = false
for (codePoint in text.message.codePoints()) { val stream = text.message.codePoints().iterator()
while (stream.hasNext()) {
val codePoint = stream.nextInt()
if (codePoint == '\n'.code) { if (codePoint == '\n'.code) {
val lineIndex = info.lineIndex
filled = renderNewline(properties, offset, info, consumer == null) filled = renderNewline(properties, offset, info, consumer == null)
info.lines[info.lineIndex - 1].push(text, line) info.lines[lineIndex].push(text, line)
skipWhitespaces = true skipWhitespaces = true
if (filled) break else continue if (filled) break else continue
} }
@ -98,11 +101,11 @@ object TextComponentRenderer : ChatComponentRenderer<TextComponent> {
val lineIndex = info.lineIndex val lineIndex = info.lineIndex
val lineInfo = renderer.render(offset, color, properties, info, formatting, codePoint, consumer, options) val lineInfo = renderer.render(offset, color, properties, info, formatting, codePoint, consumer, options)
if (consumer != null) continue // already know that information
if (lineInfo == CodePointAddResult.BREAK) { if (lineInfo == CodePointAddResult.BREAK) {
filled = true filled = true
break break
} }
if (consumer != null) continue // already know that information
if (lineIndex != info.lineIndex) { if (lineIndex != info.lineIndex) {
// new line started // new line started

View File

@ -34,12 +34,16 @@ class TextOffset(
return fits(offset.x, initial.x, info.maxSize.x, width) return fits(offset.x, initial.x, info.maxSize.x, width)
} }
fun fitsY(info: TextRenderInfo, height: Float): Boolean { fun fitsY(info: TextRenderInfo, offset: Float, height: Float): Boolean {
return fits(offset.y, initial.y, info.maxSize.y, height) return fits(this.offset.y + offset, initial.y, info.maxSize.y, height)
}
fun canEverFit(info: TextRenderInfo, width: Float): Boolean {
return info.maxSize.x >= width
} }
fun fitsInLine(properties: TextRenderProperties, info: TextRenderInfo, width: Float): Boolean { fun fitsInLine(properties: TextRenderProperties, info: TextRenderInfo, width: Float): Boolean {
return fitsX(info, width) && fitsY(info, properties.lineHeight) return fitsX(info, width) && fitsY(info, 0.0f, properties.lineHeight)
} }
fun getNextLineHeight(properties: TextRenderProperties): Float { fun getNextLineHeight(properties: TextRenderProperties): Float {
@ -49,11 +53,11 @@ class TextOffset(
return height return height
} }
fun addLine(info: TextRenderInfo, height: Float): Boolean { fun addLine(info: TextRenderInfo, offset: Float, height: Float): Boolean {
if (!fitsY(info, height)) return false if (!fitsY(info, offset, height)) return false
offset.y += height this.offset.y += height
offset.x = initial.x this.offset.x = initial.x
info.lines += TextLineInfo() info.lines += TextLineInfo()
info.lineIndex++ info.lineIndex++
@ -62,8 +66,12 @@ class TextOffset(
fun canAdd(properties: TextRenderProperties, info: TextRenderInfo, width: Float, height: Float): CodePointAddResult { fun canAdd(properties: TextRenderProperties, info: TextRenderInfo, width: Float, height: Float): CodePointAddResult {
if (!canEverFit(info, width)) {
info.cutOff = true
return CodePointAddResult.BREAK
}
if (fitsInLine(properties, info, width)) return CodePointAddResult.FINE if (fitsInLine(properties, info, width)) return CodePointAddResult.FINE
if (addLine(info, height) && fitsInLine(properties, info, width)) return CodePointAddResult.NEW_LINE if (addLine(info, 0.0f, height) && fitsInLine(properties, info, width)) return CodePointAddResult.NEW_LINE
info.cutOff = true info.cutOff = true
return CodePointAddResult.BREAK return CodePointAddResult.BREAK