mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-18 03:44:54 -04:00
gui: switches, sign editor: option to remove limit
This commit is contained in:
parent
e103543534
commit
647bfb25a5
@ -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.confirmation.ConfirmationC
|
||||
import de.bixilon.minosoft.config.profile.profiles.gui.hud.HudC
|
||||
import de.bixilon.minosoft.config.profile.profiles.gui.sign.SignC
|
||||
|
||||
/**
|
||||
* Profile for gui (rendering)
|
||||
@ -46,6 +47,7 @@ class GUIProfile(
|
||||
val chat = ChatC()
|
||||
val hud = HudC()
|
||||
val confirmation = ConfirmationC()
|
||||
val sign = SignC()
|
||||
|
||||
override fun toString(): String {
|
||||
return GUIProfileManager.getName(this)
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
@ -16,8 +16,8 @@ package de.bixilon.minosoft.config.profile.profiles.gui.confirmation
|
||||
import de.bixilon.minosoft.config.profile.profiles.gui.GUIProfileManager.delegate
|
||||
|
||||
class ConfirmationC {
|
||||
val copyToClipboard by delegate(true)
|
||||
val openFile by delegate(true)
|
||||
val openURL by delegate(true)
|
||||
val sendMessage by delegate(true)
|
||||
var copyToClipboard by delegate(true)
|
||||
var openFile by delegate(true)
|
||||
var openURL by delegate(true)
|
||||
var sendMessage by delegate(true)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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
|
||||
*/
|
||||
@Deprecated("Generally a bad idea to call")
|
||||
abstract fun forceSilentApply()
|
||||
|
||||
/**
|
||||
* Force applied all changes made to any property and calls `parent?.onChildChange(this)`
|
||||
*/
|
||||
@Deprecated("Generally a bad idea to call")
|
||||
open fun forceApply() {
|
||||
if (this is Pollable) {
|
||||
poll()
|
||||
|
@ -31,7 +31,7 @@ enum class VerticalAlignments {
|
||||
}
|
||||
|
||||
fun VerticalAlignments.getOffset(size: Vec2i, childSize: Vec2i): Vec2i {
|
||||
return Vec2i(0, getOffset(size.x, childSize.x))
|
||||
return Vec2i(0, getOffset(size.y, childSize.y))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
@ -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)
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ class TextInputElement(
|
||||
val cutAtSize: Boolean = false,
|
||||
parent: Element? = null,
|
||||
) : 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 backgroundElement = ColorElement(guiRenderer, Vec2i.EMPTY, RenderConstants.TEXT_BACKGROUND_COLOR)
|
||||
private var cursorOffset: Vec2i = Vec2i.EMPTY
|
||||
@ -117,6 +117,9 @@ class TextInputElement(
|
||||
if (newValue.length != this._value.length) {
|
||||
_set(newValue.toString())
|
||||
}
|
||||
if (_pointer > newValue.length) {
|
||||
_pointer = newValue.length
|
||||
}
|
||||
}
|
||||
|
||||
override fun forceSilentApply() {
|
||||
|
@ -21,13 +21,17 @@ import de.bixilon.kutil.cast.CastUtil.unsafeCast
|
||||
import de.bixilon.minosoft.config.key.KeyCodes
|
||||
import de.bixilon.minosoft.data.entities.block.SignBlockEntity
|
||||
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.gui.rendering.font.Font
|
||||
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.HorizontalAlignments
|
||||
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.checkbox.SwitchElement
|
||||
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.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 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 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 activeDragElement: Element? = null
|
||||
private var activeLine = 0
|
||||
@ -68,11 +73,15 @@ class SignEditorScreen(
|
||||
}
|
||||
|
||||
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?) {
|
||||
super.forceRender(offset, consumer, options)
|
||||
lengthLimitSwitch.render(offset + VerticalAlignments.BOTTOM.getOffset(size, lengthLimitSwitch.size), consumer, options)
|
||||
|
||||
val size = size
|
||||
|
||||
@ -111,9 +120,22 @@ class SignEditorScreen(
|
||||
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>? {
|
||||
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
|
||||
getAtCheck(position, headerElement, HorizontalAlignments.CENTER, true)?.let { return it }
|
||||
if (position.y < 0) {
|
||||
|
@ -1333,5 +1333,40 @@
|
||||
"start": [2, 2],
|
||||
"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 |
Loading…
x
Reference in New Issue
Block a user