From 647bfb25a569ece62d915ad0f9f62abd8cfb2baf Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sat, 23 Apr 2022 20:18:02 +0200 Subject: [PATCH] gui: switches, sign editor: option to remove limit --- .../config/profile/profiles/gui/GUIProfile.kt | 2 + .../gui/confirmation/ConfirmationC.kt | 10 +- .../config/profile/profiles/gui/sign/SignC.kt | 20 ++ .../gui/rendering/gui/elements/Element.kt | 2 - .../gui/elements/VerticalAlignments.kt | 2 +- .../input/checkbox/AbstractCheckboxElement.kt | 19 ++ .../elements/input/checkbox/SwitchElement.kt | 171 ++++++++++++++++++ .../gui/elements/input/TextInputElement.kt | 5 +- .../gui/gui/screen/SignEditorScreen.kt | 24 ++- .../assets/minosoft/mapping/atlas.json | 35 ++++ .../assets/minosoft/textures/icons.png | Bin 526 -> 664 bytes 11 files changed, 280 insertions(+), 10 deletions(-) create mode 100644 src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/sign/SignC.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/AbstractCheckboxElement.kt create mode 100644 src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/SwitchElement.kt diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/GUIProfile.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/GUIProfile.kt index 26288f305..ffbf17a01 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/GUIProfile.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/GUIProfile.kt @@ -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) diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/confirmation/ConfirmationC.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/confirmation/ConfirmationC.kt index b4be3cbfe..509c5b330 100644 --- a/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/confirmation/ConfirmationC.kt +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/confirmation/ConfirmationC.kt @@ -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) } diff --git a/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/sign/SignC.kt b/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/sign/SignC.kt new file mode 100644 index 000000000..1a67354c8 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/config/profile/profiles/gui/sign/SignC.kt @@ -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 . + * + * 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) +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt index 910cd0413..8cacc430b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/Element.kt @@ -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() diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/VerticalAlignments.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/VerticalAlignments.kt index 390d8d4b2..f6f92c94f 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/VerticalAlignments.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/VerticalAlignments.kt @@ -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)) } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/AbstractCheckboxElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/AbstractCheckboxElement.kt new file mode 100644 index 000000000..245a0d64d --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/AbstractCheckboxElement.kt @@ -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 . + * + * 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) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/SwitchElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/SwitchElement.kt new file mode 100644 index 000000000..ab09c59f4 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/input/checkbox/SwitchElement.kt @@ -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 . + * + * 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) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt index 3c5ff46ae..906373eb0 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/elements/input/TextInputElement.kt @@ -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() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/SignEditorScreen.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/SignEditorScreen.kt index b9f01a0e6..b0ccedf3a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/SignEditorScreen.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/gui/screen/SignEditorScreen.kt @@ -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()?.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()?.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? { 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) { diff --git a/src/main/resources/assets/minosoft/mapping/atlas.json b/src/main/resources/assets/minosoft/mapping/atlas.json index a2026bb43..440464468 100644 --- a/src/main/resources/assets/minosoft/mapping/atlas.json +++ b/src/main/resources/assets/minosoft/mapping/atlas.json @@ -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] + } } } diff --git a/src/main/resources/assets/minosoft/textures/icons.png b/src/main/resources/assets/minosoft/textures/icons.png index 8d71b0fff3ff62eab6b99d1f2225fed1c456f255..3c28a0bf233067677c1f6a4105a80bcf18aa12ce 100644 GIT binary patch delta 399 zcmeBUnZY{2qMpgi)5S5QV$Rz;Yx8a=NU%P5obla2)J@gxv1CVx$OUVT&X5V!62`Y} zS$w!SCG}$^tFt#`nB&iC${x{S@ix#xL;jG-406|`#Un17J0Kt z%yW*t-o9(y|J?`V%fsD`4{QjjjQq2n@7_ASBFnw2>)zSFTgO*_{q*u{JO(z4xAVp6 z&)*ci{HxA=RpvR{11G)u_xkv?3s1ki%K(}bIBC!S4@-B&#%^KTozjq4S<3(ax$56f z#dEJN&-a}4@=^IZpnW^;{(5@W;dX7^bRGkT-KBkcZ}cP?9`J;o%sltN_wt;i9I@`B zp3nM@C!hDQuzo)&#c1XitDKVk_tibO-OgQKoW417Qi|RD?^flTZ>o6C+J9=>&-BOF z_ib7ro?pkoGR2Y6;h+eEhz~i`AK?w^|2R1&Gcw*6pL3?1_h4T4-7@wp1|aZs^>bP0 Hl+XkK5@@nV delta 241 zcmVu;ZI%Ml;Whs|_8Y^KO4X@L4nDWxf;^y`2h z$JJ~D)TN2*@ZW6i`b8|eee=0Kj;m?CJ!Ko9KJ8DN>+LDVAxg5Rd`ScRZEZv}Z?6y8 zXxZ&&8=yXIM8w_wOS9`2*|4Mm>T>gj|9++4KBwrP-XkKSd;IE38lZCHaQzv`z4J>N rphDvivx8mIld%ENlfVHc7yJ_!HsV@g9OFC`00000NkvXXu0mjfAsBL=