wip buttons

This commit is contained in:
Bixilon 2022-01-18 19:37:51 +01:00
parent ad7a438895
commit 948338a1ac
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
17 changed files with 281 additions and 22 deletions

View File

@ -29,3 +29,6 @@
- Label
- Checkbox
## ToDo:
- make `TextElement`, `GridLayout` final

View File

@ -20,6 +20,7 @@ import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
interface GUIElementDrawer {
val guiRenderer: GUIRenderer
var lastTickTime: Long
fun drawElements(elements: Collection<GUIElement>, zOffset: Int): Int {
@ -53,6 +54,7 @@ interface GUIElementDrawer {
}
}
guiRenderer.setup()
for (element in elements) {
if (element !is LayoutedGUIElement<*> || !element.enabled || element.mesh.data.isEmpty) {
continue

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.gui.rendering.gui
import de.bixilon.kutil.latch.CountUpAndDownLatch
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.config.profile.delegate.watcher.SimpleProfileDelegateWatcher.Companion.profileWatchRendering
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.atlas.AtlasManager
@ -26,6 +27,7 @@ import de.bixilon.minosoft.gui.rendering.renderer.RendererBuilder
import de.bixilon.minosoft.gui.rendering.system.base.PolygonModes
import de.bixilon.minosoft.gui.rendering.system.base.buffer.frame.Framebuffer
import de.bixilon.minosoft.gui.rendering.system.base.phases.OtherDrawable
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
import de.bixilon.minosoft.modding.event.invoker.CallbackEventInvoker
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.KUtil.toResourceLocation
@ -85,11 +87,22 @@ class GUIRenderer(
shader.use()
}
override fun onMouseMove(position: Vec2i) {
gui.onMouseMove(position / profile.scale)
}
override fun onCharPress(char: Int) {
gui.onCharPress(char)
}
override fun onKeyPress(type: KeyChangeTypes, key: KeyCodes) {
gui.onKeyPress(type, key)
}
override fun drawOther() {
setup()
var z = 0
z += hud.draw(z)
z += gui.draw(z)
z += hud.draw(z) + 1
z += gui.draw(z) + 1
if (this.matrixChange) {
this.matrixChange = false
}

View File

@ -19,6 +19,7 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMeshCache
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.input.InputHandler
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isGreater
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isSmaller
@ -30,7 +31,7 @@ import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import glm_.vec2.Vec2i
import glm_.vec4.Vec4i
abstract class Element(val guiRenderer: GUIRenderer) {
abstract class Element(val guiRenderer: GUIRenderer) : InputHandler {
var ignoreDisplaySize = false
val renderWindow = guiRenderer.renderWindow
@ -148,7 +149,7 @@ abstract class Element(val guiRenderer: GUIRenderer) {
val maxZ = forceRender(offset, z, cache, options)
cache.maxZ = maxZ
if (cache.data !is DirectArrayFloatList) {
// raw mesh data
// not raw mesh data
cache.data.finish()
}
cacheUpToDate = true

View File

@ -0,0 +1,87 @@
/*
* Minosoft
* Copyright (C) 2020-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.button
import de.bixilon.minosoft.config.key.KeyCodes
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.AtlasImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
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 de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isGreater
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isSmaller
import glm_.vec2.Vec2i
class ButtonElement(
guiRenderer: GUIRenderer,
text: Any,
var onSubmit: () -> Unit,
) : Element(guiRenderer) {
private val textElement = TextElement(guiRenderer, text, background = false).apply { parent = this@ButtonElement }
private val disabledAtlas = guiRenderer.atlasManager["button_disabled"]
private val normalAtlas = guiRenderer.atlasManager["button_normal"]
private val hoveredButton = guiRenderer.atlasManager["button_hovered"]
private val background = AtlasImageElement(guiRenderer, normalAtlas ?: guiRenderer.renderWindow.WHITE_TEXTURE).apply { parent = this@ButtonElement }
var state: ButtonStates = ButtonStates.NORMAL
set(value) {
if (field == value) {
return
}
field = value
background.textureLike = when (value) {
ButtonStates.NORMAL -> normalAtlas
ButtonStates.HOVERED -> hoveredButton
} ?: renderWindow.WHITE_TEXTURE
forceApply()
}
init {
size = textElement.size + Vec2i(4, 4)
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
var zUsed = background.render(offset, z, consumer, options)
zUsed += textElement.render(offset + Vec2i(2, 2), z + zUsed, consumer, options)
return zUsed
}
override fun forceSilentApply() {
cacheUpToDate = false
background.size = size
}
override fun onKeyPress(type: KeyChangeTypes, key: KeyCodes) {
if (type == KeyChangeTypes.PRESS && key == KeyCodes.KEY_LEFT) {
submit()
}
}
override fun onMouseMove(position: Vec2i) {
state = if (position isGreater size || position isSmaller Vec2i.EMPTY) {
// move away
ButtonStates.NORMAL
} else {
ButtonStates.HOVERED
}
}
fun submit() {
onSubmit()
}
}

View File

@ -0,0 +1,19 @@
/*
* Minosoft
* Copyright (C) 2020-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.button
enum class ButtonStates {
NORMAL,
HOVERED,
}

View File

@ -27,7 +27,7 @@ import glm_.vec2.Vec2i
open class AtlasImageElement(
guiRenderer: GUIRenderer,
val textureLike: TextureLike,
textureLike: TextureLike,
size: Vec2i = textureLike.size,
tint: RGBColor = ChatColors.WHITE,
) : Element(guiRenderer) {
@ -67,6 +67,19 @@ open class AtlasImageElement(
cacheUpToDate = false
}
var textureLike: TextureLike = textureLike
set(value) {
if (field === value) {
return
}
texture = value.texture
field = value
uvStart = null
uvEnd = null
cacheUpToDate = false
}
init {
this.size = size
}

View File

@ -23,12 +23,14 @@ import de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.pause.PauseMenu
import de.bixilon.minosoft.gui.rendering.gui.hud.Initializable
import de.bixilon.minosoft.gui.rendering.gui.hud.elements.LayoutedGUIElement
import de.bixilon.minosoft.gui.rendering.input.InputHandler
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
import de.bixilon.minosoft.util.KUtil.toResourceLocation
import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogMessageType
import glm_.vec2.Vec2i
class GUIManager(
val guiRenderer: GUIRenderer,
override val guiRenderer: GUIRenderer,
) : Initializable, InputHandler, GUIElementDrawer {
var elements: MutableList<GUIElement> = mutableListOf()
private val renderWindow = guiRenderer.renderWindow
@ -36,6 +38,8 @@ class GUIManager(
override var lastTickTime: Long = -1L
override fun init() {
elements += LayoutedGUIElement(PauseMenu(guiRenderer)).apply { enabled = false }
for (element in elements) {
element.init()
}
@ -53,11 +57,17 @@ class GUIManager(
for (element in elements) {
element.postInit()
if (element is LayoutedGUIElement<*>) {
element.initMesh()
}
}
}
fun onMatrixChange() {
for (element in elements) {
if (element is LayoutedGUIElement<*>) {
element.elementLayout.silentApply()
}
element.apply()
}
}
@ -68,6 +78,9 @@ class GUIManager(
fun pause(pause: Boolean? = null) {
val nextPause = pause ?: !paused
if (nextPause == paused) {
return
}
Log.log(LogMessageType.RENDERING_GENERAL) { "Pausing: $nextPause" }
@ -77,9 +90,19 @@ class GUIManager(
null
}
paused = nextPause
if (nextPause) {
elements += LayoutedGUIElement(PauseMenu(guiRenderer))
}
elements.find { it is LayoutedGUIElement<*> && it.elementLayout is PauseMenu }?.enabled = nextPause
}
override fun onCharPress(char: Int) {
elements.getOrNull(0)?.onCharPress(char)
}
override fun onMouseMove(position: Vec2i) {
elements.getOrNull(0)?.onMouseMove(position)
}
override fun onKeyPress(type: KeyChangeTypes, key: KeyCodes) {
elements.getOrNull(0)?.onKeyPress(type, key)
}
fun goBack() {

View File

@ -25,12 +25,12 @@ import glm_.vec2.Vec2i
abstract class Screen(
guiRenderer: GUIRenderer,
) : Element(guiRenderer), LayoutedElement {
val background = AtlasImageElement(guiRenderer, renderWindow.WHITE_TEXTURE, size = guiRenderer.scaledSize, tint = RGBColor(0.0f, 0.0f, 0.0f, 0.8f))
protected val background = AtlasImageElement(guiRenderer, renderWindow.WHITE_TEXTURE, size = guiRenderer.scaledSize, tint = RGBColor(0.0f, 0.0f, 0.0f, 0.8f))
override val layoutOffset: Vec2i = Vec2i(0, 0)
init {
_size = guiRenderer.scaledSize
}
override var _size: Vec2i
get() = guiRenderer.scaledSize
set(value) {}
override fun forceSilentApply() {
background.size = guiRenderer.scaledSize

View File

@ -14,6 +14,62 @@
package de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu
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.button.ButtonElement
import de.bixilon.minosoft.gui.rendering.gui.gui.screen.Screen
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import glm_.vec2.Vec2i
abstract class Menu(guiRenderer: GUIRenderer) : Screen(guiRenderer)
abstract class Menu(guiRenderer: GUIRenderer) : Screen(guiRenderer) {
private val buttons: MutableList<ButtonElement> = mutableListOf()
private var buttonWidth = -1
private var totalHeight = -1
override fun forceSilentApply() {
buttonWidth = _size.x / 3 // 1 left and right
var totalHeight = 0
for (button in buttons) {
val currentButtonSize = button.size
val buttonSize = Vec2i(buttonWidth, currentButtonSize.y)
button.prefMaxSize = buttonSize
button.size = buttonSize
totalHeight += currentButtonSize.y
}
totalHeight += maxOf(0, (buttons.size - 1) * BUTTON_Y_MARGIN)
this.totalHeight = totalHeight
super.forceSilentApply()
cacheUpToDate = false
}
fun addButton(button: ButtonElement) {
button.parent = this
buttons += button
forceSilentApply()
}
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
val size = size
var zUsed = super.forceRender(offset, z, consumer, options)
val startOffset = (size - Vec2i(buttonWidth, totalHeight)) / 2
for (button in buttons) {
zUsed = maxOf(zUsed, button.render(offset + startOffset, z + zUsed, consumer, options) + zUsed)
startOffset.y += BUTTON_Y_MARGIN + button.size.y
}
return zUsed
}
override fun onMouseMove(position: Vec2i) {
buttons.getOrNull(0)?.onMouseMove(position)
}
override fun onChildChange(child: Element) {
cacheUpToDate = false
}
private companion object {
const val BUTTON_Y_MARGIN = 5
}
}

View File

@ -14,6 +14,13 @@
package de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.pause
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.button.ButtonElement
import de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.Menu
class PauseMenu(guiRenderer: GUIRenderer) : Menu(guiRenderer)
class PauseMenu(guiRenderer: GUIRenderer) : Menu(guiRenderer) {
init {
addButton(ButtonElement(guiRenderer, "Print message") {
println("Printed!")
})
}
}

View File

@ -38,10 +38,9 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.elements.title.TitleElement
import de.bixilon.minosoft.util.KUtil.toResourceLocation
class HUDManager(
val guiRenderer: GUIRenderer,
override val guiRenderer: GUIRenderer,
) : GUIElementDrawer, Initializable {
val renderWindow = guiRenderer.renderWindow
private val connection = renderWindow.connection
private val hudElements: MutableMap<ResourceLocation, HUDElement> = synchronizedMapOf()

View File

@ -14,6 +14,7 @@
package de.bixilon.minosoft.gui.rendering.gui.hud.elements
import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.gui.rendering.RenderWindow
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
@ -22,8 +23,10 @@ import de.bixilon.minosoft.gui.rendering.gui.hud.HUDElement
import de.bixilon.minosoft.gui.rendering.gui.hud.Initializable
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIMesh
import de.bixilon.minosoft.gui.rendering.renderer.Drawable
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
import de.bixilon.minosoft.gui.rendering.util.mesh.Mesh
import de.bixilon.minosoft.util.collections.floats.DirectArrayFloatList
import glm_.vec2.Vec2i
class LayoutedGUIElement<T : LayoutedElement>(
val layout: T,
@ -86,4 +89,16 @@ class LayoutedGUIElement<T : LayoutedElement>(
elementLayout.cache.data = mesh.data
mesh.load()
}
override fun onMouseMove(position: Vec2i) {
elementLayout.onMouseMove(position)
}
override fun onCharPress(char: Int) {
elementLayout.onCharPress(char)
}
override fun onKeyPress(type: KeyChangeTypes, key: KeyCodes) {
elementLayout.onKeyPress(type, key)
}
}

View File

@ -14,11 +14,12 @@
package de.bixilon.minosoft.gui.rendering.input
import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
import glm_.vec2.Vec2i
interface InputHandler {
fun onMouseMove(position: Vec2i) {}
fun onKeyPress(key: KeyCodes) {}
fun onKeyPress(type: KeyChangeTypes, key: KeyCodes) {}
fun onCharPress(char: Int) {}
}

View File

@ -35,6 +35,7 @@ object DefaultKeyCombinations {
KeyAction.MODIFIER to setOf(KeyCodes.KEY_F4),
KeyAction.STICKY to setOf(KeyCodes.KEY_P),
),
ignoreConsumer = true,
)) {
val nextMode = it.decide(PolygonModes.LINE, PolygonModes.FILL)
renderWindow.framebufferManager.world.polygonMode = nextMode

View File

@ -125,9 +125,7 @@ class RenderWindowInputHandler(
skipKeyPress = false
return
}
if (keyChangeType == KeyChangeTypes.PRESS || keyChangeType == KeyChangeTypes.REPEAT) {
inputHandler.onKeyPress(keyCode)
}
inputHandler.onKeyPress(keyChangeType, keyCode)
}
val keyDown = when (keyChangeType) {

View File

@ -685,5 +685,26 @@
}
}
}
},
"minecraft:button_disabled": {
"0": {
"texture": "minecraft:textures/gui/widgets.png",
"start": [0, 46],
"end": [200, 66]
}
},
"minecraft:button_normal": {
"0": {
"texture": "minecraft:textures/gui/widgets.png",
"start": [0, 66],
"end": [200, 86]
}
},
"minecraft:button_hovered": {
"0": {
"texture": "minecraft:textures/gui/widgets.png",
"start": [0, 86],
"end": [200, 106]
}
}
}