aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThunderblade73 <85900443+Thunderblade73@users.noreply.github.com>2024-09-07 16:14:23 +0200
committerGitHub <noreply@github.com>2024-09-07 16:14:23 +0200
commit9d326f9c6bcbb62b120a33930a23f223667cd040 (patch)
tree4c3d599ff846fa32bc5ac28aaf84980e138b87f7
parent53b85119ef0961f7088357107e335c308168e4e2 (diff)
downloadskyhanni-9d326f9c6bcbb62b120a33930a23f223667cd040.tar.gz
skyhanni-9d326f9c6bcbb62b120a33930a23f223667cd040.tar.bz2
skyhanni-9d326f9c6bcbb62b120a33930a23f223667cd040.zip
Backend: Renderable searchbox (#2475)
-rw-r--r--src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt41
-rw-r--r--src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiScreen.java6
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt106
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt12
4 files changed, 156 insertions, 9 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt
index d7e6ff8e1..6ae2342b6 100644
--- a/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt
+++ b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt
@@ -8,6 +8,7 @@ import at.hannibal2.skyhanni.utils.StringUtils.insert
import kotlinx.coroutines.runBlocking
import net.minecraft.client.settings.KeyBinding
import org.lwjgl.input.Keyboard
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
class TextInput {
@@ -22,16 +23,35 @@ class TextInput {
}
}.replace("(?<!§.\\|)§(?!.\\|§.)".toRegex(), "&&")
+ fun editTextWithAlwaysCarriage() = textBox.let {
+ with(carriage) {
+ if (this == null) it.plus('|')
+ else it.insert(this, '|')
+ }
+ }.replace("§", "&&")
+
fun finalText() = textBox.replace("&&", "§")
- fun makeActive() = Companion.activate(this)
- fun disable() = Companion.disable()
+ fun makeActive() = if (!isActive) Companion.activate(this) else Unit
+ fun disable() = if (isActive) Companion.disable() else Unit
fun handle() = Companion.handleTextInput()
fun clear() {
textBox = ""
carriage = null
}
+ val isActive get() = Companion.activeInstance == this
+
+ private val updateEvents = mutableMapOf<Int, (TextInput) -> Unit>()
+
+ fun registerToEvent(key: Int, event: (TextInput) -> Unit) {
+ updateEvents[key] = event
+ }
+
+ fun removeFromEvent(key: Int) {
+ updateEvents.remove(key)
+ }
+
companion object {
private var activeInstance: TextInput? = null
@@ -51,6 +71,13 @@ class TextInput {
}
}
+ fun onGuiInput(ci: CallbackInfo) {
+ if (activeInstance != null) {
+ ci.cancel()
+ return
+ }
+ }
+
private var timeSinceKeyEvent = 0L
private var carriage
@@ -65,6 +92,13 @@ class TextInput {
activeInstance?.textBox = value
}
+ private fun updated() {
+ with(activeInstance) {
+ if (this == null) return
+ this.updateEvents.forEach { (_, it) -> it(this) }
+ }
+ }
+
private fun handleTextInput() {
if (KeyboardManager.isCopyingKeysDown()) {
OSUtils.copyToClipboard(textBox)
@@ -73,6 +107,7 @@ class TextInput {
if (KeyboardManager.isPastingKeysDown()) {
runBlocking {
textBox = OSUtils.readFromClipboard() ?: return@runBlocking
+ updated()
}
return
}
@@ -96,6 +131,7 @@ class TextInput {
} else {
textBox.dropLast(1)
}
+ updated()
return
}
@@ -122,6 +158,7 @@ class TextInput {
textBox + char
}
}
+ updated()
}
private fun moveCarriageRight(carriage: Int) = carriage + 1
diff --git a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiScreen.java b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiScreen.java
index b14d225cf..b3338acf5 100644
--- a/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiScreen.java
+++ b/src/main/java/at/hannibal2/skyhanni/mixins/transformers/gui/MixinGuiScreen.java
@@ -1,6 +1,7 @@
package at.hannibal2.skyhanni.mixins.transformers.gui;
import at.hannibal2.skyhanni.data.ToolTipData;
+import at.hannibal2.skyhanni.data.model.TextInput;
import at.hannibal2.skyhanni.mixins.hooks.GuiScreenHookKt;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.item.ItemStack;
@@ -27,4 +28,9 @@ public class MixinGuiScreen {
ci.cancel();
}
}
+
+ @Inject(method = "handleKeyboardInput", at = @At("HEAD"), cancellable = true)
+ public void handleKeyboardInput(CallbackInfo ci) {
+ TextInput.Companion.onGuiInput(ci);
+ }
}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt
index 29105459c..a49f58b00 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt
@@ -5,6 +5,7 @@ import at.hannibal2.skyhanni.config.features.skillprogress.SkillProgressBarConfi
import at.hannibal2.skyhanni.data.GuiData
import at.hannibal2.skyhanni.data.HighlightOnHoverSlot
import at.hannibal2.skyhanni.data.ToolTipData
+import at.hannibal2.skyhanni.data.model.TextInput
import at.hannibal2.skyhanni.features.chroma.ChromaShaderManager
import at.hannibal2.skyhanni.features.chroma.ChromaType
import at.hannibal2.skyhanni.features.misc.DarkenShader
@@ -52,7 +53,11 @@ interface Renderable {
val horizontalAlign: HorizontalAlignment
val verticalAlign: VerticalAlignment
fun isHovered(posX: Int, posY: Int) = currentRenderPassMousePosition?.let { (x, y) ->
- x in (posX..posX + width) && y in (posY..posY + height) // TODO: adjust for variable height?
+ x in (posX..posX + width) && y in (posY..posY + height)
+ } ?: false
+
+ fun isBoxHovered(posX: Int, width: Int, posY: Int, height: Int) = currentRenderPassMousePosition?.let { (x, y) ->
+ x in (posX..posX + width) && y in (posY..posY + height)
} ?: false
/**
@@ -435,12 +440,7 @@ interface Renderable {
val inverseScale = 1 / scale
override fun render(posX: Int, posY: Int) {
- val fontRenderer = Minecraft.getMinecraft().fontRendererObj
- GlStateManager.translate(1.0, 1.0, 0.0)
- GlStateManager.scale(scale, scale, 1.0)
- fontRenderer.drawStringWithShadow(text, 0f, 0f, color.rgb)
- GlStateManager.scale(inverseScale, inverseScale, 1.0)
- GlStateManager.translate(-1.0, -1.0, 0.0)
+ RenderableUtils.renderString(text, scale, color, inverseScale)
}
}
@@ -534,6 +534,98 @@ interface Renderable {
}
}
+ /**
+ * @param searchPrefix text that is static in front of the textbox
+ * @param onUpdateSize function that is called if the size changes (since the search text can get bigger than [content])
+ * @param textInput The text input, can be external or internal
+ * @param shouldRenderTopElseBottom true == Renders on top, false == Renders at the Bottom
+ * @param hideIfNoText hides text box if no input is given
+ * @param ySpacing space between the search and [content]
+ * @param onHover is triggered if [content] or the text box is hovered
+ * @param bypassChecks bypass the [shouldAllowLink] logic
+ * @param condition condition to being able to input / [onHover] to trigger
+ * @param scale text scale of the textbox
+ * @param color color of the textbox
+ * @param key event key for the [textInput] to register the event, needs clearing if [textInput] is external, default = 0
+ */
+ fun searchBox(
+ content: Renderable,
+ searchPrefix: String,
+ onUpdateSize: (Renderable) -> Unit,
+ textInput: TextInput = TextInput(),
+ shouldRenderTopElseBottom: Boolean = true,
+ hideIfNoText: Boolean = true,
+ ySpacing: Int = 0,
+ onHover: (TextInput) -> Unit = {},
+ bypassChecks: Boolean = false,
+ condition: () -> Boolean = { true },
+ scale: Double = 1.0,
+ color: Color = Color.WHITE,
+ key: Int = 0,
+ ) = object : Renderable {
+
+ val textBoxHeight = (9 * scale).toInt() + 1
+
+ override var width: Int = content.width
+ override val height: Int = content.height + ySpacing + textBoxHeight
+ override val horizontalAlign = content.horizontalAlign
+ override val verticalAlign = content.verticalAlign
+
+ val searchWidth get() = (Minecraft.getMinecraft().fontRendererObj.getStringWidth(searchPrefix + textInput.editTextWithAlwaysCarriage()) * scale).toInt() + 1
+
+ init {
+ textInput.registerToEvent(key) {
+ val searchWidth = searchWidth
+ if (searchWidth > width) {
+ width = searchWidth
+ onUpdateSize(this)
+ } else {
+ if (width > content.width) {
+ width = maxOf(content.width, searchWidth)
+ onUpdateSize(this)
+ }
+ }
+ }
+ }
+
+ override fun render(posX: Int, posY: Int) {
+ if (shouldRenderTopElseBottom) {
+ if (!(hideIfNoText && textInput.textBox.isEmpty())) {
+ RenderableUtils.renderString(searchPrefix + textInput.editText(), scale, color)
+ }
+ GlStateManager.translate(0f, (ySpacing + textBoxHeight).toFloat(), 0f)
+ }
+ if (isHovered(posX, posY) && condition() && shouldAllowLink(true, bypassChecks)) {
+ onHover(textInput)
+ textInput.makeActive()
+ textInput.handle()
+ val yOff: Int
+ if (shouldRenderTopElseBottom) {
+ yOff = 0
+ } else {
+ yOff = content.height + ySpacing
+ }
+ if (isBoxHovered(posX, width, posY + yOff, textBoxHeight) && (-99).isKeyClicked()) {
+ textInput.clear()
+ }
+ } else {
+ textInput.disable()
+ }
+ if (!shouldRenderTopElseBottom) {
+ content.render(posX, posY)
+ GlStateManager.translate(0f, (ySpacing).toFloat(), 0f)
+ if (!(hideIfNoText && textInput.textBox.isEmpty())) {
+ RenderableUtils.renderString(searchPrefix + textInput.editText(), scale, color)
+ }
+ GlStateManager.translate(0f, -(ySpacing).toFloat(), 0f)
+ } else {
+ content.render(posX, posY + textBoxHeight + ySpacing)
+ GlStateManager.translate(0f, -(ySpacing + textBoxHeight).toFloat(), 0f)
+ }
+ }
+
+ }
+
fun progressBar(
percent: Double,
startColor: Color = Color(255, 0, 0),
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt
index a78044d72..4a8f28c8e 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt
@@ -2,7 +2,9 @@ package at.hannibal2.skyhanni.utils.renderables
import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment
import at.hannibal2.skyhanni.utils.RenderUtils.VerticalAlignment
+import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.GlStateManager
+import java.awt.Color
internal object RenderableUtils {
@@ -72,6 +74,16 @@ internal object RenderableUtils {
GlStateManager.translate(0f, -yOffset.toFloat(), 0f)
return yOffset
}
+
+ @Suppress("NOTHING_TO_INLINE")
+ inline fun renderString(text: String, scale: Double = 1.0, color: Color = Color.WHITE, inverseScale: Double = 1 / scale) {
+ val fontRenderer = Minecraft.getMinecraft().fontRendererObj
+ GlStateManager.translate(1.0, 1.0, 0.0)
+ GlStateManager.scale(scale, scale, 1.0)
+ fontRenderer.drawStringWithShadow(text, 0f, 0f, color.rgb)
+ GlStateManager.scale(inverseScale, inverseScale, 1.0)
+ GlStateManager.translate(-1.0, -1.0, 0.0)
+ }
}
internal abstract class RenderableWrapper internal constructor(protected val content: Renderable) : Renderable {