gui: switches, sign editor: option to remove limit

This commit is contained in:
Bixilon 2022-04-23 20:18:02 +02:00
parent e103543534
commit 647bfb25a5
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
11 changed files with 280 additions and 10 deletions

View File

@ -21,6 +21,7 @@ import de.bixilon.minosoft.config.profile.profiles.gui.GUIProfileManager.latestV
import de.bixilon.minosoft.config.profile.profiles.gui.chat.ChatC import de.bixilon.minosoft.config.profile.profiles.gui.chat.ChatC
import de.bixilon.minosoft.config.profile.profiles.gui.confirmation.ConfirmationC import de.bixilon.minosoft.config.profile.profiles.gui.confirmation.ConfirmationC
import de.bixilon.minosoft.config.profile.profiles.gui.hud.HudC import de.bixilon.minosoft.config.profile.profiles.gui.hud.HudC
import de.bixilon.minosoft.config.profile.profiles.gui.sign.SignC
/** /**
* Profile for gui (rendering) * Profile for gui (rendering)
@ -46,6 +47,7 @@ class GUIProfile(
val chat = ChatC() val chat = ChatC()
val hud = HudC() val hud = HudC()
val confirmation = ConfirmationC() val confirmation = ConfirmationC()
val sign = SignC()
override fun toString(): String { override fun toString(): String {
return GUIProfileManager.getName(this) return GUIProfileManager.getName(this)

View File

@ -1,6 +1,6 @@
/* /*
* Minosoft * Minosoft
* Copyright (C) 2022 Moritz Zwerger * 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 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.
* *
@ -16,8 +16,8 @@ package de.bixilon.minosoft.config.profile.profiles.gui.confirmation
import de.bixilon.minosoft.config.profile.profiles.gui.GUIProfileManager.delegate import de.bixilon.minosoft.config.profile.profiles.gui.GUIProfileManager.delegate
class ConfirmationC { class ConfirmationC {
val copyToClipboard by delegate(true) var copyToClipboard by delegate(true)
val openFile by delegate(true) var openFile by delegate(true)
val openURL by delegate(true) var openURL by delegate(true)
val sendMessage by delegate(true) var sendMessage by delegate(true)
} }

View File

@ -0,0 +1,20 @@
/*
* 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.config.profile.profiles.gui.sign
import de.bixilon.minosoft.config.profile.profiles.gui.GUIProfileManager.delegate
class SignC {
var limitLength by delegate(true)
}

View File

@ -199,13 +199,11 @@ abstract class Element(val guiRenderer: GUIRenderer, var initialCacheSize: Int =
/** /**
* Force applies all changes made to any property, but does not notify the parent about the change * Force applies all changes made to any property, but does not notify the parent about the change
*/ */
@Deprecated("Generally a bad idea to call")
abstract fun forceSilentApply() abstract fun forceSilentApply()
/** /**
* Force applied all changes made to any property and calls `parent?.onChildChange(this)` * Force applied all changes made to any property and calls `parent?.onChildChange(this)`
*/ */
@Deprecated("Generally a bad idea to call")
open fun forceApply() { open fun forceApply() {
if (this is Pollable) { if (this is Pollable) {
poll() poll()

View File

@ -31,7 +31,7 @@ enum class VerticalAlignments {
} }
fun VerticalAlignments.getOffset(size: Vec2i, childSize: Vec2i): Vec2i { fun VerticalAlignments.getOffset(size: Vec2i, childSize: Vec2i): Vec2i {
return Vec2i(0, getOffset(size.x, childSize.x)) return Vec2i(0, getOffset(size.y, childSize.y))
} }
} }
} }

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.input.checkbox
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.elements.Element
abstract class AbstractCheckboxElement(guiRenderer: GUIRenderer) : Element(guiRenderer)

View File

@ -0,0 +1,171 @@
/*
* 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.input.checkbox
import de.bixilon.kotlinglm.vec2.Vec2i
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.VerticalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments.Companion.getOffset
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.input.mouse.MouseActions
import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons
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.CursorShapes
import de.bixilon.minosoft.gui.rendering.system.window.KeyChangeTypes
import de.bixilon.minosoft.util.KUtil.toResourceLocation
open class SwitchElement(
guiRenderer: GUIRenderer,
text: Any,
state: Boolean = false,
disabled: Boolean = false,
parent: Element?,
var onChange: (state: Boolean) -> Unit,
) : AbstractCheckboxElement(guiRenderer) {
protected val textElement = TextElement(guiRenderer, text, background = false).apply { this.parent = this@SwitchElement }
private val disabledAtlas = guiRenderer.atlasManager["minosoft:switch_disabled"]
private val normalAtlas = guiRenderer.atlasManager["minosoft:switch_normal"]
private val hoveredAtlas = guiRenderer.atlasManager["minosoft:switch_hovered"]
private val onStateAtlas = guiRenderer.atlasManager["minosoft:switch_state_on"]
private val offStateAtlas = guiRenderer.atlasManager["minosoft:switch_state_off"]
var state: Boolean = state
set(value) {
if (field == value) {
return
}
field = value
onChange(state)
forceApply()
}
var disabled: Boolean = disabled
set(value) {
if (field == value) {
return
}
field = value
forceApply()
}
var hovered: Boolean = false
private set(value) {
if (field == value) {
return
}
field = value
forceApply()
}
override val canFocus: Boolean
get() = !disabled
init {
size = SIZE + Vec2i(5 + TEXT_MARGIN + textElement.size.x, 0)
this.parent = parent
}
override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
val texture = when {
disabled -> disabledAtlas
hovered -> hoveredAtlas
else -> normalAtlas
} ?: guiRenderer.renderWindow.WHITE_TEXTURE
val size = size
val background = AtlasImageElement(guiRenderer, texture)
background.size = SIZE
background.render(offset, consumer, options)
if (state) {
AtlasImageElement(guiRenderer, onStateAtlas, size = SLIDER_SIZE).render(offset + Vec2i(SIZE.x - SLIDER_SIZE.x, 0), consumer, options)
} else {
AtlasImageElement(guiRenderer, offStateAtlas, size = SLIDER_SIZE).render(offset, consumer, options)
}
textElement.render(offset + Vec2i(SIZE.x + TEXT_MARGIN, VerticalAlignments.CENTER.getOffset(size.y, textElement.size.y)), consumer, options)
}
override fun forceSilentApply() {
textElement.silentApply()
cacheUpToDate = false
}
override fun onMouseAction(position: Vec2i, button: MouseButtons, action: MouseActions, count: Int): Boolean {
if (disabled) {
return true
}
if (button != MouseButtons.LEFT) {
return true
}
if (action != MouseActions.PRESS) {
return true
}
switchState()
return true
}
override fun onKey(key: KeyCodes, type: KeyChangeTypes): Boolean {
if (!hovered) {
return true
}
if (disabled) {
return true
}
if (key != KeyCodes.KEY_ENTER) {
return true
}
if (type != KeyChangeTypes.PRESS) {
return true
}
switchState()
return true
}
override fun onMouseEnter(position: Vec2i, absolute: Vec2i): Boolean {
hovered = true
renderWindow.window.cursorShape = CursorShapes.HAND
return true
}
override fun onMouseLeave(): Boolean {
hovered = false
renderWindow.window.resetCursor()
return true
}
open fun switchState() {
state = !state
if (guiRenderer.connection.profiles.audio.gui.button) {
guiRenderer.connection.world.play2DSound(CLICK_SOUND)
}
}
private companion object {
val CLICK_SOUND = "minecraft:ui.button.click".toResourceLocation()
const val TEXT_MARGIN = 5
val SIZE = Vec2i(30, 20)
val SLIDER_SIZE = Vec2i(6, 20)
}
}

View File

@ -47,7 +47,7 @@ class TextInputElement(
val cutAtSize: Boolean = false, val cutAtSize: Boolean = false,
parent: Element? = null, parent: Element? = null,
) : Element(guiRenderer) { ) : Element(guiRenderer) {
private val cursor = ColorElement(guiRenderer, size = Vec2i(1, Font.TOTAL_CHAR_HEIGHT * scale)) private val cursor = ColorElement(guiRenderer, size = Vec2i(minOf(1.0f, scale), Font.TOTAL_CHAR_HEIGHT * scale))
private val textElement = MarkTextElement(guiRenderer, "", background = false, parent = this, scale = scale, shadow = shadow) private val textElement = MarkTextElement(guiRenderer, "", background = false, parent = this, scale = scale, shadow = shadow)
private val backgroundElement = ColorElement(guiRenderer, Vec2i.EMPTY, RenderConstants.TEXT_BACKGROUND_COLOR) private val backgroundElement = ColorElement(guiRenderer, Vec2i.EMPTY, RenderConstants.TEXT_BACKGROUND_COLOR)
private var cursorOffset: Vec2i = Vec2i.EMPTY private var cursorOffset: Vec2i = Vec2i.EMPTY
@ -117,6 +117,9 @@ class TextInputElement(
if (newValue.length != this._value.length) { if (newValue.length != this._value.length) {
_set(newValue.toString()) _set(newValue.toString())
} }
if (_pointer > newValue.length) {
_pointer = newValue.length
}
} }
override fun forceSilentApply() { override fun forceSilentApply() {

View File

@ -21,13 +21,17 @@ import de.bixilon.kutil.cast.CastUtil.unsafeCast
import de.bixilon.minosoft.config.key.KeyCodes import de.bixilon.minosoft.config.key.KeyCodes
import de.bixilon.minosoft.data.entities.block.SignBlockEntity import de.bixilon.minosoft.data.entities.block.SignBlockEntity
import de.bixilon.minosoft.data.registries.blocks.BlockState import de.bixilon.minosoft.data.registries.blocks.BlockState
import de.bixilon.minosoft.data.registries.blocks.types.entity.sign.SignBlock
import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.gui.rendering.font.Font import de.bixilon.minosoft.gui.rendering.font.Font
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.HorizontalAlignments import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments
import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments.Companion.getOffset
import de.bixilon.minosoft.gui.rendering.gui.elements.input.button.ButtonElement import de.bixilon.minosoft.gui.rendering.gui.elements.input.button.ButtonElement
import de.bixilon.minosoft.gui.rendering.gui.elements.input.checkbox.SwitchElement
import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ImageElement
import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement
import de.bixilon.minosoft.gui.rendering.gui.gui.AbstractLayout import de.bixilon.minosoft.gui.rendering.gui.gui.AbstractLayout
@ -56,6 +60,7 @@ class SignEditorScreen(
private val backgroundElement = ImageElement(guiRenderer, getTexture(), uvStart = SIGN_UV_START, uvEnd = SIGN_UV_END, size = BACKGROUND_SIZE) private val backgroundElement = ImageElement(guiRenderer, getTexture(), uvStart = SIGN_UV_START, uvEnd = SIGN_UV_END, size = BACKGROUND_SIZE)
private val lines = Array(SignBlockEntity.LINES) { TextInputElement(guiRenderer, blockEntity?.lines?.get(it)?.message ?: "", 256, scale = TEXT_SCALE, background = false, cutAtSize = true, parent = this) } private val lines = Array(SignBlockEntity.LINES) { TextInputElement(guiRenderer, blockEntity?.lines?.get(it)?.message ?: "", 256, scale = TEXT_SCALE, background = false, cutAtSize = true, parent = this) }
private val doneButton = ButtonElement(guiRenderer, "Done") { guiRenderer.gui.pop() }.apply { size = Vec2i(BACKGROUND_SIZE.x, size.y);parent = this@SignEditorScreen } private val doneButton = ButtonElement(guiRenderer, "Done") { guiRenderer.gui.pop() }.apply { size = Vec2i(BACKGROUND_SIZE.x, size.y);parent = this@SignEditorScreen }
private val lengthLimitSwitch = SwitchElement(guiRenderer, "Limit length", guiRenderer.connection.profiles.gui.sign.limitLength, parent = this) { guiRenderer.connection.profiles.gui.sign.limitLength = it; forceSilentApply() }
override var activeElement: Element? = null override var activeElement: Element? = null
override var activeDragElement: Element? = null override var activeDragElement: Element? = null
private var activeLine = 0 private var activeLine = 0
@ -68,11 +73,15 @@ class SignEditorScreen(
} }
private fun getTexture(): AbstractTexture? { private fun getTexture(): AbstractTexture? {
return blockState?.blockModel?.nullCast<BakedBlockStateModel>()?.faces?.firstOrNull()?.firstOrNull()?.texture ?: guiRenderer.atlasManager["minecraft:sign_front"]?.texture if (blockState?.block !is SignBlock) {
return guiRenderer.atlasManager["minecraft:sign_front"]?.texture
}
return blockState.blockModel?.nullCast<BakedBlockStateModel>()?.faces?.firstOrNull()?.firstOrNull()?.texture ?: guiRenderer.atlasManager["minecraft:sign_front"]?.texture
} }
override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) { override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
super.forceRender(offset, consumer, options) super.forceRender(offset, consumer, options)
lengthLimitSwitch.render(offset + VerticalAlignments.BOTTOM.getOffset(size, lengthLimitSwitch.size), consumer, options)
val size = size val size = size
@ -111,9 +120,22 @@ class SignEditorScreen(
guiRenderer.connection.sendPacket(SignTextC2SP(blockPosition, text)) guiRenderer.connection.sendPacket(SignTextC2SP(blockPosition, text))
} }
override fun forceSilentApply() {
super.forceSilentApply()
for (line in lines) {
line.prefMaxSize = Vec2i(if (lengthLimitSwitch.state) SignBlockEntityRenderer.SIGN_MAX_WIDTH * TEXT_SCALE else -1, line.prefMaxSize.y)
}
}
override fun getAt(position: Vec2i): Pair<Element, Vec2i>? { override fun getAt(position: Vec2i): Pair<Element, Vec2i>? {
val size = size val size = size
if (position.y in size.y - lengthLimitSwitch.size.y..size.y) {
position.y -= size.y - lengthLimitSwitch.size.y
getAtCheck(position, lengthLimitSwitch, HorizontalAlignments.LEFT, false)?.let { return it }
}
position.y -= size.y / 8 position.y -= size.y / 8
getAtCheck(position, headerElement, HorizontalAlignments.CENTER, true)?.let { return it } getAtCheck(position, headerElement, HorizontalAlignments.CENTER, true)?.let { return it }
if (position.y < 0) { if (position.y < 0) {

View File

@ -1333,5 +1333,40 @@
"start": [2, 2], "start": [2, 2],
"end": [26, 14] "end": [26, 14]
} }
},
"minosoft:switch_normal": {
"0": {
"texture": "minosoft:textures/icons.png",
"start": [0, 10],
"end": [30, 31]
}
},
"minosoft:switch_disabled": {
"0": {
"texture": "minosoft:textures/icons.png",
"start": [30, 10],
"end": [60, 31]
}
},
"minosoft:switch_hovered": {
"0": {
"texture": "minosoft:textures/icons.png",
"start": [60, 10],
"end": [90, 31]
}
},
"minosoft:switch_state_off": {
"0": {
"texture": "minosoft:textures/icons.png",
"start": [90, 10],
"end": [96, 31]
}
},
"minosoft:switch_state_on": {
"0": {
"texture": "minosoft:textures/icons.png",
"start": [96, 10],
"end": [102, 31]
}
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 B

After

Width:  |  Height:  |  Size: 664 B