Files
Terrarum/src/net/torvald/terrarum/ui/UIItemTextSelector.kt
2024-04-01 03:15:57 +09:00

290 lines
11 KiB
Kotlin

package net.torvald.terrarum.ui
import com.badlogic.gdx.graphics.Camera
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.ui.UIItemAccessibilityUtil.playHapticCursorHovered
import net.torvald.terrarum.ui.UIItemAccessibilityUtil.playHapticPushedDown
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
/**
* @param width width of the text input where the text gets drawn, not the entire item
* @param height height of the text input where the text gets drawn, not the entire item
*
* Created by minjaesong on 2021-10-21.
*/
class UIItemTextSelector(
parentUI: UICanvas,
initialX: Int, initialY: Int,
val labelfuns: List<() -> String>,
initialSelection: Int,
override val width: Int,
private val drawBorder: Boolean = true,
private val clickToShowPalette: Boolean = true,
private val useSpinnerButtons: Boolean = false,
private val font: TerrarumSansBitmap = App.fontGame
) : UIItem(parentUI, initialX, initialY) {
init {
}
override val mouseUp: Boolean
get() = (itemRelativeMouseX in 0 until width && itemRelativeMouseY in 0 until height) or (if (paletteShowing)
(itemRelativeMouseX in buttonW + 3 until buttonW + 3 + palW &&
itemRelativeMouseY in palY - posY until palY + palH - posY)
else false)
private val labels = CommonResourcePool.getAsTextureRegionPack("inventory_category")
override val height = 24
private val buttonW = 30
private val fboWidth = width - 2*buttonW - 6
// private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, fboWidth, height - 4, false)
var selection = initialSelection
private var fboUpdateLatch = true
private var mouseOnButton = 0 // 0: nothing, 1: left, 2: right, 3: middle
var selectionChangeListener: (Int) -> Unit = {}
private var mouseOnPaletteItem: Int? = null
var paletteShowing = false; private set
private val palCursorCol = Toolkit.Theme.COL_INACTIVE.cpy().mul(1f,1f,1f,0.5f)
private val palCellHeight = height // must be same as the text area height
private val palCursorGap = 6 // preferably multiple of 3
private var palX = posX + buttonW + 3
private var palY = posY - palCellHeight * selection - palCursorGap
private var palW = width - 2*buttonW - 6
private var palH = palCellHeight * labelfuns.size + 2*palCursorGap
private var labelCache: List<String> = listOf()
override fun show() {
fboUpdateLatch = true
}
private var oldMouseOnButton = 0
private var oldMouseOnPaletteItem: Int? = null
override fun update(delta: Float) {
super.update(delta)
mouseOnButton =
if (itemRelativeMouseX in 0 until buttonW && itemRelativeMouseY in 0 until height)
1
else if (itemRelativeMouseX in width - buttonW until width && itemRelativeMouseY in 0 until height)
2
else if (itemRelativeMouseX in buttonW + 3 until width - buttonW - 3 && itemRelativeMouseY in 0 until height)
3
else
0
mouseOnPaletteItem = null // serves as the fallback value
if (paletteShowing) {
for (i in 0 until labelfuns.size) {
val ys = getPalItemPosY(i) - 2 // text cell height is hardcoded as 24; text height is 20
val ye = ys + palCellHeight
// cannot use mouseOnButton == 3 as it also takes Y-position into account
if (parentUI.relativeMouseY in ys until ye && itemRelativeMouseX in buttonW + 3 until width - buttonW - 3) {
mouseOnPaletteItem = i
break
}
}
}
mouseLatch.latch {
if (paletteShowing && mouseOnPaletteItem != null) {
selection = mouseOnPaletteItem!!
fboUpdateLatch = true
selectionChangeListener(selection)
paletteShowing = false
}
else if (mouseOnButton in 1..2) {
selection = (selection + (mouseOnButton * 2) - 3) fmod labelfuns.size
fboUpdateLatch = true
selectionChangeListener(selection)
paletteShowing = false
}
else if (mouseOnButton == 3 && clickToShowPalette) {
if (!paletteShowing) {
paletteShowing = true
}
else {
paletteShowing = false
selectionChangeListener(selection)
}
}
else {
paletteShowing = false
}
if (mouseOnButton > 0 && (clickToShowPalette || mouseOnButton != 3)) {
playHapticPushedDown()
}
}
if (mouseOnButton > 0 && mouseOnButton != oldMouseOnButton) {
if (drawBorder || mouseOnButton != 2)
playHapticCursorHovered()
}
else if (mouseOnPaletteItem != null && mouseOnPaletteItem != oldMouseOnPaletteItem) {
playHapticCursorHovered()
}
oldMouseOnButton = mouseOnButton
oldMouseOnPaletteItem = mouseOnPaletteItem
}
private val leftIcon = if (useSpinnerButtons) labels.get(9,2) else labels.get(16,0)
private val rightIcon = if (useSpinnerButtons) labels.get(10,2) else labels.get(17,0)
override fun render(frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera) {
labelCache = labelfuns.map { it() }
batch.end()
/*if (fboUpdateLatch) {
fboUpdateLatch = false
fbo.inAction(camera as OrthographicCamera, batch) { batch.inUse {
gdxClearAndEnableBlend(0f, 0f, 0f, 0f)
it.color = Color.WHITE
val t = labelCache[selection]
val tw = font.getWidth(t)
printdbg(this, "Drawing text: $t")
App.fontGameFBO.draw(it, t, (fbo.width - tw) / 2, 0)
} }
}*/
batch.begin()
if (drawBorder) {
batch.color = UIItemTextLineInput.TEXTINPUT_COL_BACKGROUND
// left button cell back
Toolkit.fillArea(batch, posX, posY, buttonW, height)
// text area cell back
Toolkit.fillArea(batch, posX + buttonW + 3, posY, width - 2*buttonW - 6, height)
// right button cell back
Toolkit.fillArea(batch, posX + width - buttonW, posY, buttonW, height)
// text area border
if (!paletteShowing && mouseOnButton != 3) {
batch.color = Toolkit.Theme.COL_INACTIVE
Toolkit.drawBoxBorder(batch, posX - 1, posY - 1, width + 2, height + 2)
}
// left button border
batch.color = if (mouseOnButton == 1 && mousePushed) Toolkit.Theme.COL_SELECTED
else if (mouseOnButton == 1) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_INACTIVE
Toolkit.drawBoxBorder(batch, posX - 1, posY - 1, buttonW + 2, height + 2)
// right button border
batch.color = if (mouseOnButton == 2 && mousePushed) Toolkit.Theme.COL_SELECTED
else if (mouseOnButton == 2) Toolkit.Theme.COL_MOUSE_UP else Toolkit.Theme.COL_INACTIVE
Toolkit.drawBoxBorder(batch, posX + width - buttonW - 1, posY - 1, buttonW + 2, height + 2)
// text area border (again)
if (!paletteShowing && mouseOnButton == 3) {
batch.color = Toolkit.Theme.COL_MOUSE_UP
Toolkit.drawBoxBorder(batch, posX + buttonW + 2, posY - 1, width - 2*buttonW - 4, height + 2)
}
}
// left button icon
batch.color = if (mouseOnButton == 1 && mousePushed) Toolkit.Theme.COL_SELECTED
else if (mouseOnButton == 1) Toolkit.Theme.COL_MOUSE_UP else UIItemTextLineInput.TEXTINPUT_COL_TEXT
batch.draw(leftIcon, posX + (buttonW - labels.tileW) / 2f, posY + (height - labels.tileH) / 2f)
// right button icon
batch.color = if (mouseOnButton == 2 && mousePushed) Toolkit.Theme.COL_SELECTED
else if (mouseOnButton == 2) Toolkit.Theme.COL_MOUSE_UP else UIItemTextLineInput.TEXTINPUT_COL_TEXT
batch.draw(rightIcon, posX + width - buttonW + (buttonW - labels.tileW) / 2f, posY + (height - labels.tileH) / 2f)
// draw text
if (!paletteShowing) {
batch.color = UIItemTextLineInput.TEXTINPUT_COL_TEXT
val t = labelCache[selection]
val tw = font.getWidth(t)
// batch.draw(fbo.colorBufferTexture, posX + buttonW + 3f, posY + 2f, fbo.width.toFloat(), fbo.height.toFloat())
font.draw(batch, t, posX + buttonW + 3 + (fboWidth - tw) / 2, posY)
}
// palette
else {
palX = posX + buttonW + 3
palY = posY - palCellHeight * selection - palCursorGap
palH = palCellHeight * labelCache.size + 2*palCursorGap
// palette background
batch.color = UIItemTextLineInput.TEXTINPUT_COL_BACKGROUND
Toolkit.fillArea(batch, palX-1, palY-1, palW+2, palH+2)
Toolkit.fillArea(batch, palX-1, palY-1, palW+2, palH+2)
// cursor
batch.color = palCursorCol
Toolkit.drawBoxBorder(batch, posX + buttonW + 2, posY - 1, width - 2*buttonW - 4, height + 2)
// palette border
batch.color = Toolkit.Theme.COL_MOUSE_UP
Toolkit.drawBoxBorder(batch, palX-1, palY-1, palW+2, palH+2)
// palette items
labelCache.forEachIndexed { index, s ->
batch.color = if (index == selection) Toolkit.Theme.COL_SELECTED
else if (index == mouseOnPaletteItem) Toolkit.Theme.COL_MOUSE_UP
else UIItemTextLineInput.TEXTINPUT_COL_TEXT
val t = labelCache[index]
val tw = font.getWidth(t)
font.draw(batch, t,
palX + (palW - tw) / 2,
getPalItemPosY(index) - 2
)
}
}
super.render(frameDelta, batch, camera)
}
/**
* posY, palY and selection must be updated beforehand!
*/
private fun getPalItemPosY(index: Int) = palY + 2 + palCellHeight * index +
(if (index > selection) 1 else if (index == selection) 0 else -1) * palCursorGap + palCursorGap
override fun scrolled(amountX: Float, amountY: Float): Boolean {
if (mouseUp) {
if (amountX <= -1 || amountY <= -1)
selection = (selection - 1) fmod labelfuns.size
else if (amountX >= 1 || amountY >= 1)
selection = (selection + 1) fmod labelfuns.size
selectionChangeListener(selection)
fboUpdateLatch = true
playHapticPushedDown()
return true
}
else {
return false
}
}
override fun dispose() {
// fbo.dispose()
}
}