2021-02-19 04:12:43 +00:00
|
|
|
package net.shadowfacts.cacao.view
|
|
|
|
|
|
|
|
import net.minecraft.client.MinecraftClient
|
|
|
|
import net.minecraft.client.font.TextRenderer
|
|
|
|
import net.minecraft.client.util.math.MatrixStack
|
2021-02-27 18:24:17 +00:00
|
|
|
import net.minecraft.text.LiteralText
|
2021-02-27 04:23:11 +00:00
|
|
|
import net.minecraft.text.OrderedText
|
|
|
|
import net.minecraft.text.Text
|
2021-02-19 04:12:43 +00:00
|
|
|
import net.shadowfacts.cacao.geometry.Point
|
|
|
|
import net.shadowfacts.cacao.geometry.Size
|
|
|
|
import net.shadowfacts.cacao.util.Color
|
|
|
|
import net.shadowfacts.cacao.util.RenderHelper
|
2021-03-05 00:44:31 +00:00
|
|
|
import kotlin.math.min
|
2021-02-19 04:12:43 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A simple View that displays text. Allows for controlling the color and shadow of the text. Label cannot be used
|
|
|
|
* for multi-line text, instead use [TextView].
|
|
|
|
*
|
|
|
|
* @author shadowfacts
|
|
|
|
* @param text The text of this label.
|
|
|
|
* @param shadow Whether the text should be rendered with a shadow or not.
|
|
|
|
* @param maxLines The maximum number of lines of text to render.
|
|
|
|
* `0` means that there is no line limit and all lines will be rendered.
|
|
|
|
* When using a non-zero [maxLines] value, the [intrinsicContentSize] of the Label still assumes all
|
|
|
|
* content on one line. So, constraints must be provided to calculate the actual width to use for line
|
|
|
|
* wrapping.
|
|
|
|
*/
|
|
|
|
class Label(
|
2021-02-27 04:23:11 +00:00
|
|
|
text: Text,
|
2021-03-05 00:44:31 +00:00
|
|
|
var shadow: Boolean = false,
|
2021-02-19 04:12:43 +00:00
|
|
|
val maxLines: Int = 0,
|
|
|
|
val wrappingMode: WrappingMode = WrappingMode.WRAP,
|
2021-03-05 00:44:31 +00:00
|
|
|
var textAlignment: TextAlignment = TextAlignment.LEFT
|
2021-02-19 04:12:43 +00:00
|
|
|
): View() {
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
private val textRenderer: TextRenderer
|
|
|
|
get() = MinecraftClient.getInstance().textRenderer
|
|
|
|
}
|
|
|
|
|
|
|
|
enum class WrappingMode {
|
|
|
|
WRAP, NO_WRAP
|
|
|
|
}
|
|
|
|
|
|
|
|
enum class TextAlignment {
|
|
|
|
LEFT, CENTER, RIGHT
|
|
|
|
}
|
|
|
|
|
2021-02-27 18:24:17 +00:00
|
|
|
constructor(
|
|
|
|
text: String,
|
2021-02-28 02:48:40 +00:00
|
|
|
shadow: Boolean = false,
|
2021-02-27 18:24:17 +00:00
|
|
|
maxLines: Int = 0,
|
|
|
|
wrappingMode: WrappingMode = WrappingMode.WRAP,
|
|
|
|
textAlignment: TextAlignment = TextAlignment.LEFT,
|
|
|
|
): this(LiteralText(text), shadow, maxLines, wrappingMode, textAlignment)
|
|
|
|
|
2021-02-19 04:12:43 +00:00
|
|
|
/**
|
|
|
|
* The text of this label. Mutating this field will update the intrinsic content size and trigger a layout.
|
|
|
|
*/
|
2021-02-27 04:23:11 +00:00
|
|
|
var text: Text = text
|
2021-02-19 04:12:43 +00:00
|
|
|
set(value) {
|
|
|
|
field = value
|
2021-03-05 00:44:31 +00:00
|
|
|
// todo: uhhhh
|
|
|
|
updateIntrinsicContentSize(true)
|
2021-02-19 04:12:43 +00:00
|
|
|
// todo: setNeedsLayout instead of force unwrapping window
|
|
|
|
window!!.layout()
|
|
|
|
}
|
2021-02-27 04:23:11 +00:00
|
|
|
private lateinit var lines: List<OrderedText>
|
2021-02-19 04:12:43 +00:00
|
|
|
|
|
|
|
var textColor = Color.WHITE
|
|
|
|
set(value) {
|
|
|
|
field = value
|
|
|
|
textColorARGB = value.argb
|
|
|
|
}
|
|
|
|
private var textColorARGB: Int = textColor.argb
|
|
|
|
|
|
|
|
override fun wasAdded() {
|
|
|
|
super.wasAdded()
|
|
|
|
|
2021-03-05 00:44:31 +00:00
|
|
|
updateIntrinsicContentSize(false)
|
2021-02-19 04:12:43 +00:00
|
|
|
}
|
|
|
|
|
2021-03-12 22:15:36 +00:00
|
|
|
private fun updateIntrinsicContentSize(canWrap: Boolean, isFromDidLayout: Boolean = false): Boolean {
|
2021-03-05 00:44:31 +00:00
|
|
|
if (RenderHelper.disabled) return false
|
|
|
|
|
|
|
|
val oldSize = intrinsicContentSize
|
2021-03-12 22:15:36 +00:00
|
|
|
// don't wrap until we've laid out without wrapping to ensure the current bounds reflect the maximum available space
|
|
|
|
if (wrappingMode == WrappingMode.WRAP && canWrap && hasSolver && isFromDidLayout) {
|
2021-03-05 00:44:31 +00:00
|
|
|
val lines = textRenderer.wrapLines(text, bounds.width.toInt())
|
|
|
|
val height = (if (maxLines == 0) lines.size else min(lines.size, maxLines)) * textRenderer.fontHeight
|
|
|
|
intrinsicContentSize = Size(bounds.width, height.toDouble())
|
|
|
|
} else {
|
|
|
|
val width = textRenderer.getWidth(text)
|
|
|
|
val height = textRenderer.fontHeight
|
|
|
|
intrinsicContentSize = Size(width.toDouble(), height.toDouble())
|
|
|
|
}
|
|
|
|
return oldSize != intrinsicContentSize
|
2021-02-19 04:12:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun drawContent(matrixStack: MatrixStack, mouse: Point, delta: Float) {
|
|
|
|
if (!this::lines.isInitialized) {
|
|
|
|
computeLines()
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i in 0 until lines.size) {
|
|
|
|
val x = when (textAlignment) {
|
|
|
|
TextAlignment.LEFT -> 0.0
|
2021-03-03 03:20:25 +00:00
|
|
|
TextAlignment.CENTER -> (bounds.width - textRenderer.getWidth(lines[i])) / 2
|
2021-02-19 04:12:43 +00:00
|
|
|
TextAlignment.RIGHT -> bounds.width - textRenderer.getWidth(lines[i])
|
|
|
|
}
|
|
|
|
val y = i * textRenderer.fontHeight
|
|
|
|
if (shadow) {
|
|
|
|
textRenderer.drawWithShadow(matrixStack, lines[i], x.toFloat(), y.toFloat(), textColorARGB)
|
|
|
|
} else {
|
|
|
|
textRenderer.draw(matrixStack, lines[i], x.toFloat(), y.toFloat(), textColorARGB)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun didLayout() {
|
|
|
|
super.didLayout()
|
|
|
|
|
|
|
|
computeLines()
|
2021-03-12 22:15:36 +00:00
|
|
|
if (updateIntrinsicContentSize(true, true)) {
|
2021-03-05 00:44:31 +00:00
|
|
|
// if the intrinsic content size changes, relayout
|
|
|
|
window!!.layout()
|
|
|
|
}
|
2021-02-19 04:12:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun computeLines() {
|
2021-03-05 00:44:31 +00:00
|
|
|
if (wrappingMode == WrappingMode.WRAP) {
|
|
|
|
var lines = textRenderer.wrapLines(text, bounds.width.toInt())
|
|
|
|
if (maxLines > 0 && maxLines < lines.size) {
|
|
|
|
lines = lines.dropLast(lines.size - maxLines)
|
|
|
|
}
|
|
|
|
this.lines = lines
|
|
|
|
} else {
|
|
|
|
this.lines = listOf(text.asOrderedText())
|
2021-02-19 04:12:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-27 04:23:11 +00:00
|
|
|
}
|