fix crash when shutting down; improve element handling of menu

This commit is contained in:
Bixilon 2022-01-25 14:03:53 +01:00
parent 1f010c44a6
commit dc4c54d069
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
6 changed files with 76 additions and 56 deletions

View File

@ -40,7 +40,8 @@ class AboutController : EmbeddedJavaFXController<HBox>() {
bixilonLogoFX.children.setAll(JavaFXUtil.BIXILON_LOGO) bixilonLogoFX.children.setAll(JavaFXUtil.BIXILON_LOGO)
versionStringFX.text = RunConfiguration.VERSION_STRING versionStringFX.text = RunConfiguration.VERSION_STRING
aboutTextFX.text = """ aboutTextFX.text =
"""
No clue what to put here :( No clue what to put here :(
""" """
} }

View File

@ -1,6 +1,6 @@
/* /*
* Minosoft * Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger * Copyright (C) 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 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.
* *
@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft. * This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/ */
package de.bixilon.minosoft.gui.rendering.gui.elements.button package de.bixilon.minosoft.gui.rendering.gui.elements.input.button
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer 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.Element
@ -32,6 +32,7 @@ import glm_.vec2.Vec2i
open class ButtonElement( open class ButtonElement(
guiRenderer: GUIRenderer, guiRenderer: GUIRenderer,
text: Any, text: Any,
disabled: Boolean = false,
var onSubmit: () -> Unit, var onSubmit: () -> Unit,
) : Element(guiRenderer) { ) : Element(guiRenderer) {
protected val textElement = TextElement(guiRenderer, text, background = false).apply { parent = this@ButtonElement } protected val textElement = TextElement(guiRenderer, text, background = false).apply { parent = this@ButtonElement }
@ -58,7 +59,7 @@ open class ButtonElement(
super.size = value // will call forceApply super.size = value // will call forceApply
} }
var disabled: Boolean = false var disabled: Boolean = disabled
set(value) { set(value) {
if (field == value) { if (field == value) {
return return
@ -103,6 +104,9 @@ open class ButtonElement(
} }
override fun onMouseAction(position: Vec2i, button: MouseButtons, action: MouseActions) { override fun onMouseAction(position: Vec2i, button: MouseButtons, action: MouseActions) {
if (disabled) {
return
}
if (button != MouseButtons.LEFT) { if (button != MouseButtons.LEFT) {
return return
} }
@ -117,6 +121,9 @@ open class ButtonElement(
if (!hovered) { if (!hovered) {
return return
} }
if (disabled) {
return
}
if (key != InputSpecialKey.KEY_ENTER) { if (key != InputSpecialKey.KEY_ENTER) {
return return
} }

View File

@ -11,7 +11,7 @@
* This software is not affiliated with Mojang AB, the original developer of Minecraft. * This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/ */
package de.bixilon.minosoft.gui.rendering.gui.elements.button package de.bixilon.minosoft.gui.rendering.gui.elements.input.button
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
@ -19,8 +19,9 @@ open class ConfirmButtonElement(
guiRenderer: GUIRenderer, guiRenderer: GUIRenderer,
val text: Any, val text: Any,
val confirmText: Any, val confirmText: Any,
disabled: Boolean = false,
onSubmit: () -> Unit, onSubmit: () -> Unit,
) : ButtonElement(guiRenderer, text, onSubmit) { ) : ButtonElement(guiRenderer, text, disabled, onSubmit) {
private var confirming = false private var confirming = false
override fun submit() { override fun submit() {

View File

@ -15,7 +15,7 @@ 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.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element 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.elements.input.button.ButtonElement
import de.bixilon.minosoft.gui.rendering.gui.gui.screen.Screen import de.bixilon.minosoft.gui.rendering.gui.gui.screen.Screen
import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions
import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons
@ -23,26 +23,29 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import glm_.vec2.Vec2i import glm_.vec2.Vec2i
abstract class Menu(guiRenderer: GUIRenderer) : Screen(guiRenderer) { abstract class Menu(
private val buttons: MutableList<ButtonElement> = mutableListOf() guiRenderer: GUIRenderer,
val preferredElementWidth: Int = 150,
) : Screen(guiRenderer) {
private val elements: MutableList<Element> = mutableListOf()
private var buttonWidth = -1 private var elementWidth = -1
private var totalHeight = -1 private var totalHeight = -1
private var activeButton: ButtonElement? = null private var activeElement: Element? = null
override fun forceSilentApply() { override fun forceSilentApply() {
buttonWidth = size.x / 3 // 1 left and right elementWidth = maxOf(minOf(preferredElementWidth, size.x / 3), 0)
var totalHeight = 0 var totalHeight = 0
for (button in buttons) { for (element in elements) {
val currentButtonSize = button.size val currentButtonSize = element.size
val buttonSize = Vec2i(buttonWidth, currentButtonSize.y) val elementSize = Vec2i(elementWidth, currentButtonSize.y)
button.prefMaxSize = buttonSize element.prefMaxSize = elementSize
button.size = buttonSize element.size = elementSize
totalHeight += currentButtonSize.y totalHeight += currentButtonSize.y
} }
totalHeight += maxOf(0, (buttons.size - 1) * BUTTON_Y_MARGIN) totalHeight += maxOf(0, (elements.size - 1) * BUTTON_Y_MARGIN)
this.totalHeight = totalHeight this.totalHeight = totalHeight
super.forceSilentApply() super.forceSilentApply()
cacheUpToDate = false cacheUpToDate = false
@ -50,70 +53,75 @@ abstract class Menu(guiRenderer: GUIRenderer) : Screen(guiRenderer) {
fun addButton(button: ButtonElement) { fun addButton(button: ButtonElement) {
button.parent = this button.parent = this
buttons += button elements += button
forceSilentApply() forceSilentApply()
} }
override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int { override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int {
val size = size val size = size
var zUsed = super.forceRender(offset, z, consumer, options) var zUsed = super.forceRender(offset, z, consumer, options)
val startOffset = (size - Vec2i(buttonWidth, totalHeight)) / 2 val startOffset = (size - Vec2i(elementWidth, totalHeight)) / 2
for (button in buttons) { for (element in elements) {
zUsed = maxOf(zUsed, button.render(offset + startOffset, z + zUsed, consumer, options) + zUsed) zUsed = maxOf(zUsed, element.render(offset + startOffset, z + zUsed, consumer, options) + zUsed)
startOffset.y += BUTTON_Y_MARGIN + button.size.y startOffset.y += BUTTON_Y_MARGIN + element.size.y
} }
return zUsed return zUsed
} }
override fun onMouseLeave() { override fun onMouseLeave() {
activeButton?.onMouseLeave() activeElement?.onMouseLeave()
activeButton = null activeElement = null
} }
override fun onMouseMove(position: Vec2i) { override fun onMouseMove(position: Vec2i) {
val (delta, button) = getButtonAndPositionAt(position) val (delta, element) = getAt(position)
if (activeButton != button) { if (activeElement != element) {
activeButton?.onMouseLeave() activeElement?.onMouseLeave()
button?.onMouseEnter(delta) element?.onMouseEnter(delta)
activeButton = button activeElement = element
return return
} }
button?.onMouseMove(delta) element?.onMouseMove(delta)
} }
override fun onMouseAction(position: Vec2i, button: MouseButtons, action: MouseActions) { override fun onMouseAction(position: Vec2i, button: MouseButtons, action: MouseActions) {
val (delta, buttonElement) = getButtonAndPositionAt(position) val (delta, element) = getAt(position)
buttonElement?.onMouseAction(delta, button, action) element?.onMouseAction(delta, button, action)
} }
override fun onChildChange(child: Element) { override fun onChildChange(child: Element) {
forceSilentApply() forceSilentApply()
} }
fun getButtonAndPositionAt(position: Vec2i): Pair<Vec2i, ButtonElement?> { fun getAt(position: Vec2i): Pair<Vec2i, Element?> {
var delta = position val delta = Vec2i(position)
var button: ButtonElement? = null var element: Element? = null
if (position.x in buttonWidth..buttonWidth * 2) { val elementWidth = elementWidth
// x matches val size = size
val yStart = (size.y - totalHeight) / 2 val xStart = (size.x - elementWidth) / 2
var yOffset = position.y - yStart if (position.x < xStart || position.x >= xStart + elementWidth) {
for (buttonEntry in buttons) { return Pair(Vec2i(0, 0), null)
if (yOffset < 0) {
break
}
val buttonSize = buttonEntry.size
if (yOffset < buttonSize.y) {
button = buttonEntry
break
}
yOffset -= buttonSize.y
yOffset -= BUTTON_Y_MARGIN
}
delta = Vec2i(position.x - buttonWidth, yOffset)
} }
delta.x = position.x - xStart
// x matches
val yStart = (size.y - totalHeight) / 2
var yOffset = position.y - yStart
for (buttonEntry in elements) {
if (yOffset < 0) {
break
}
val buttonSize = buttonEntry.size
if (yOffset < buttonSize.y) {
element = buttonEntry
break
}
yOffset -= buttonSize.y
yOffset -= BUTTON_Y_MARGIN
}
delta.y = yOffset
return Pair(delta, button) return Pair(delta, element)
} }
private companion object { private companion object {

View File

@ -14,8 +14,8 @@
package de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.pause 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.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.button.ButtonElement import de.bixilon.minosoft.gui.rendering.gui.elements.input.button.ButtonElement
import de.bixilon.minosoft.gui.rendering.gui.elements.button.ConfirmButtonElement import de.bixilon.minosoft.gui.rendering.gui.elements.input.button.ConfirmButtonElement
import de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.Menu import de.bixilon.minosoft.gui.rendering.gui.gui.screen.menu.Menu
import de.bixilon.minosoft.util.ShutdownManager import de.bixilon.minosoft.util.ShutdownManager
@ -23,6 +23,7 @@ class PauseMenu(guiRenderer: GUIRenderer) : Menu(guiRenderer) {
init { init {
addButton(ButtonElement(guiRenderer, "Back to game") { guiRenderer.gui.pause(false) }) addButton(ButtonElement(guiRenderer, "Back to game") { guiRenderer.gui.pause(false) })
addButton(ButtonElement(guiRenderer, "Debug options", disabled = true) { TODO() })
addButton(ConfirmButtonElement(guiRenderer, "§cDisconnect", "§cClick again to disconnect!") { guiRenderer.connection.network.disconnect() }) addButton(ConfirmButtonElement(guiRenderer, "§cDisconnect", "§cClick again to disconnect!") { guiRenderer.connection.network.disconnect() })
addButton(ConfirmButtonElement(guiRenderer, "§4Exit", "§4Click again to exit!") { guiRenderer.connection.network.disconnect(); ShutdownManager.shutdown() }) addButton(ConfirmButtonElement(guiRenderer, "§4Exit", "§4Click again to exit!") { guiRenderer.connection.network.disconnect(); ShutdownManager.shutdown() })
} }

View File

@ -21,6 +21,7 @@ import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.util.logging.Log import de.bixilon.minosoft.util.logging.Log
import de.bixilon.minosoft.util.logging.LogLevels import de.bixilon.minosoft.util.logging.LogLevels
import de.bixilon.minosoft.util.logging.LogMessageType import de.bixilon.minosoft.util.logging.LogMessageType
import javafx.application.Platform
import kotlin.system.exitProcess import kotlin.system.exitProcess
object ShutdownManager { object ShutdownManager {
@ -35,6 +36,7 @@ object ShutdownManager {
} }
FileWatcherService.stop() FileWatcherService.stop()
DefaultThreadPool.shutdownNow() DefaultThreadPool.shutdownNow()
Platform.exit()
exitProcess(reason.exitCode) exitProcess(reason.exitCode)
} }