aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorThunderblade73 <85900443+Thunderblade73@users.noreply.github.com>2024-04-30 18:16:05 +0200
committerGitHub <noreply@github.com>2024-04-30 18:16:05 +0200
commit249e02778ce9543afc515ee4c7b5a57e154ac61d (patch)
tree44412cbbf98c5aa370e50e6599861ff556b73c50 /src/main/java
parent7f26ff46f3a537f1561b33d9bb513a81509f855b (diff)
downloadskyhanni-249e02778ce9543afc515ee4c7b5a57e154ac61d.tar.gz
skyhanni-249e02778ce9543afc515ee4c7b5a57e154ac61d.tar.bz2
skyhanni-249e02778ce9543afc515ee4c7b5a57e154ac61d.zip
Backend: Renderable scrollables (#886)
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt3
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt131
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/ScrollInput.kt85
3 files changed, 219 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
index f538f2d53..df4f15e47 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
@@ -148,6 +148,9 @@ object CollectionUtils {
return this
}
+ operator fun IntRange.contains(range: IntRange): Boolean =
+ range.first in this && range.last in this
+
fun <E> MutableList<List<E>>.addAsSingletonList(text: E) {
add(Collections.singletonList(text))
}
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 09591c62d..304e31141 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt
@@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.data.HighlightOnHoverSlot
import at.hannibal2.skyhanni.data.ToolTipData
import at.hannibal2.skyhanni.features.chroma.ChromaShaderManager
import at.hannibal2.skyhanni.features.chroma.ChromaType
+import at.hannibal2.skyhanni.utils.CollectionUtils.contains
import at.hannibal2.skyhanni.utils.ColorUtils
import at.hannibal2.skyhanni.utils.ColorUtils.darker
import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyClicked
@@ -590,6 +591,136 @@ interface Renderable {
}
}
+ fun scrollList(
+ list: List<Renderable>,
+ height: Int,
+ scrollValue: ScrollValue = ScrollValue(),
+ velocity: Double = 2.0,
+ button: Int? = null,
+ horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
+ verticalAlign: VerticalAlignment = VerticalAlignment.TOP,
+ ) = object : Renderable {
+ override val width = list.maxOf { it.width }
+ override val height = height
+ override val horizontalAlign = horizontalAlign
+ override val verticalAlign = verticalAlign
+
+ private val virtualHeight = list.sumOf { it.height }
+
+ private val scroll = ScrollInput.Companion.Vertical(
+ scrollValue,
+ 0,
+ virtualHeight - height,
+ velocity,
+ button
+ )
+
+ private val end get() = scroll.asInt() + height
+
+ override fun render(posX: Int, posY: Int) {
+ scroll.update(
+ isHovered(posX, posY)
+ )
+
+ var renderY = 0
+ var virtualY = 0
+ var found = false
+ list.forEach {
+ if ((virtualY..virtualY + it.height) in scroll.asInt()..end) {
+ it.renderXAligned(posX, posY + renderY, width)
+ GlStateManager.translate(0f, it.height.toFloat(), 0f)
+ renderY += it.height
+ found = true
+ } else if (found) {
+ found = false
+ if (renderY + it.height <= height) {
+ it.renderXAligned(posX, posY + renderY, width)
+ }
+ return@forEach
+ }
+ virtualY += it.height
+ }
+ GlStateManager.translate(0f, -renderY.toFloat(), 0f)
+ }
+ }
+
+ fun scrollTable(
+ content: List<List<Renderable?>>,
+ height: Int,
+ scrollValue: ScrollValue = ScrollValue(),
+ velocity: Double = 2.0,
+ button: Int? = null,
+ xPadding: Int = 1,
+ yPadding: Int = 0,
+ hasHeader: Boolean = false,
+ horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
+ verticalAlign: VerticalAlignment = VerticalAlignment.TOP,
+ ) = object : Renderable {
+
+ val xOffsets: List<Int> = calculateTableXOffsets(content, xPadding)
+ val yOffsets: List<Int> = calculateTableYOffsets(content, yPadding)
+
+ override val width = xOffsets.last() - xPadding
+ override val height = height
+ override val horizontalAlign = horizontalAlign
+ override val verticalAlign = verticalAlign
+
+ private val virtualHeight = yOffsets.last() - yPadding
+
+ private val end get() = scroll.asInt() + height - yPadding - 1
+
+ private val scroll = ScrollInput.Companion.Vertical(
+ scrollValue,
+ if (hasHeader) yOffsets[1] else 0,
+ virtualHeight - height,
+ velocity,
+ button
+ )
+
+ override fun render(posX: Int, posY: Int) {
+ scroll.update(
+ isHovered(posX, posY)
+ )
+
+ var renderY = 0
+ if (hasHeader) {
+ content[0].forEachIndexed { index, renderable ->
+ GlStateManager.translate(xOffsets[index].toFloat(), 0f, 0f)
+ renderable?.renderXYAligned(
+ posX + xOffsets[index],
+ posY + renderY,
+ xOffsets[index + 1] - xOffsets[index],
+ yOffsets[1]
+ )
+ GlStateManager.translate(-xOffsets[index].toFloat(), 0f, 0f)
+ }
+ val yShift = yOffsets[1] - yOffsets[0]
+ GlStateManager.translate(0f, yShift.toFloat(), 0f)
+ renderY += yShift
+ }
+ val range =
+ yOffsets.indexOfFirst { it >= scroll.asInt() }..<(yOffsets.indexOfFirst { it >= end }
+ .takeIf { it > 0 }
+ ?: yOffsets.size) - 1
+ for (rowIndex in range) {
+ content[rowIndex].forEachIndexed { index, renderable ->
+ GlStateManager.translate(xOffsets[index].toFloat(), 0f, 0f)
+ renderable?.renderXYAligned(
+ posX + xOffsets[index],
+ posY + renderY,
+ xOffsets[index + 1] - xOffsets[index],
+ yOffsets[rowIndex + 1] - yOffsets[rowIndex]
+ )
+ GlStateManager.translate(-xOffsets[index].toFloat(), 0f, 0f)
+ }
+ val yShift = yOffsets[rowIndex + 1] - yOffsets[rowIndex]
+ GlStateManager.translate(0f, yShift.toFloat(), 0f)
+ renderY += yShift
+ }
+ GlStateManager.translate(0f, -renderY.toFloat(), 0f)
+ }
+ }
+
fun drawInsideRoundedRect(
input: Renderable,
color: Color,
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/renderables/ScrollInput.kt b/src/main/java/at/hannibal2/skyhanni/utils/renderables/ScrollInput.kt
new file mode 100644
index 000000000..e47cca31c
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/ScrollInput.kt
@@ -0,0 +1,85 @@
+package at.hannibal2.skyhanni.utils.renderables
+
+import org.lwjgl.input.Mouse
+
+abstract class ScrollInput(
+ private val scrollValue: ScrollValue,
+ protected val minValue: Int,
+ protected val maxValue: Int,
+ protected val velocity: Double,
+ protected val dragScrollMouseButton: Int?,
+ startValue: Double?
+) {
+
+ init {
+ scrollValue.init(startValue ?: minValue.toDouble())
+ coerceInLimit()
+ }
+
+ protected var scroll
+ set(value) {
+ scrollValue.setValue(value)
+ }
+ get() = scrollValue.getValue()
+
+ private var mouseEventTime = 0L
+
+ fun asInt() = scroll.toInt()
+ fun asDouble() = scroll
+
+ protected fun coerceInLimit() =
+ if (maxValue < minValue) {
+ scroll = minValue.toDouble()
+ } else {
+ scroll = scroll.coerceIn(minValue.toDouble(), maxValue.toDouble())
+ }
+
+ protected fun isMouseEventValid(): Boolean {
+ val mouseEvent = Mouse.getEventNanoseconds()
+ val mouseEventsValid = mouseEvent - mouseEventTime > 20L
+ mouseEventTime = mouseEvent
+ return mouseEventsValid
+ }
+
+ abstract fun update(isValid: Boolean)
+
+ companion object {
+
+ class Vertical(
+ scrollValue: ScrollValue,
+ minHeight: Int,
+ maxHeight: Int,
+ velocity: Double,
+ dragScrollMouseButton: Int?,
+ startValue: Double? = null
+ ) : ScrollInput(scrollValue, minHeight, maxHeight, velocity, dragScrollMouseButton, startValue) {
+ override fun update(isValid: Boolean) {
+ if (maxValue < minValue) return
+ if (!isValid || !isMouseEventValid()) return
+ if (dragScrollMouseButton != null && Mouse.isButtonDown(dragScrollMouseButton)) {
+ scroll += Mouse.getEventDY() * velocity
+ }
+ val deltaWheel = Mouse.getEventDWheel()
+ scroll += -deltaWheel.coerceIn(-1, 1) * 2.5 * velocity
+ coerceInLimit()
+ }
+
+ }
+ }
+}
+
+class ScrollValue {
+ var field: Double? = null
+ fun getValue(): Double =
+ field ?: throw IllegalStateException("ScrollValue should be initialized before get.")
+
+ fun setValue(value: Double) {
+ field = value
+ }
+
+ fun init(value: Double) {
+ if (field != null) return
+ field = value
+ }
+
+}