aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/utils
diff options
context:
space:
mode:
authorThunderblade73 <85900443+Thunderblade73@users.noreply.github.com>2024-06-05 15:39:55 +0200
committerGitHub <noreply@github.com>2024-06-05 15:39:55 +0200
commit5a04ad230cc4fb94884b34f795124d3b65af07ea (patch)
treecace8dcaad1c989be42a52bff4a6da233642279f /src/main/java/at/hannibal2/skyhanni/utils
parenteb4ab6eaafa17581df58a53fb4111fa96933d230 (diff)
downloadskyhanni-5a04ad230cc4fb94884b34f795124d3b65af07ea.tar.gz
skyhanni-5a04ad230cc4fb94884b34f795124d3b65af07ea.tar.bz2
skyhanni-5a04ad230cc4fb94884b34f795124d3b65af07ea.zip
Improvement: Refactor of /ff for Improved Modularity and Code Reusability (#873)
Co-authored-by: Cal <cwolfson58@gmail.com>
Diffstat (limited to 'src/main/java/at/hannibal2/skyhanni/utils')
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt43
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/GuiRenderUtils.kt176
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt9
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/guide/GuideGUI.kt121
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/guide/GuidePage.kt15
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/guide/GuideRenderablePage.kt23
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/guide/GuideScrollPage.kt31
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTab.kt67
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTablePage.kt33
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt117
-rw-r--r--src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt11
11 files changed, 499 insertions, 147 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
index 2e1237fe8..48cf1ccb2 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt
@@ -2,11 +2,13 @@ package at.hannibal2.skyhanni.utils
import at.hannibal2.skyhanni.utils.NEUItems.getItemStack
import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.renderables.RenderableUtils
import net.minecraft.enchantment.Enchantment
import net.minecraft.item.ItemStack
import java.util.Collections
import java.util.Queue
import java.util.WeakHashMap
+import kotlin.math.ceil
object CollectionUtils {
@@ -279,6 +281,38 @@ object CollectionUtils {
}))
}
+ fun Collection<Collection<Renderable>>.tableStretchXPadding(xSpace: Int): Int {
+ if (this.isEmpty()) return xSpace
+ val off = RenderableUtils.calculateTableXOffsets(this as List<List<Renderable?>>, 0)
+ val xLength = off.size - 1
+ val emptySpace = xSpace - off.last()
+ if (emptySpace < 0) {
+ // throw IllegalArgumentException("Not enough space for content")
+ }
+ return emptySpace / (xLength - 1)
+ }
+
+ fun Collection<Collection<Renderable>>.tableStretchYPadding(ySpace: Int): Int {
+ if (this.isEmpty()) return ySpace
+ val off = RenderableUtils.calculateTableYOffsets(this as List<List<Renderable?>>, 0)
+ val yLength = off.size - 1
+ val emptySpace = ySpace - off.last()
+ if (emptySpace < 0) {
+ // throw IllegalArgumentException("Not enough space for content")
+ }
+ return emptySpace / (yLength - 1)
+ }
+
+ /** Splits the input into equal sized lists. If the list can't get divided clean by [subs] then the last entry gets reduced. e.g. 13/4 = [4,4,4,1]*/
+ fun <T> Collection<T>.split(subs: Int = 2): List<List<T>> {
+ if (this.isEmpty()) return listOf(emptyList())
+ val list = this.chunked(ceil(this.size.toDouble() / subs.toDouble()).toInt()).toMutableList()
+ while (list.size < subs) {
+ list.add(emptyList())
+ }
+ return list
+ }
+
inline fun <K, V, R : Any> Map<K, V>.mapKeysNotNull(transform: (Map.Entry<K, V>) -> R?): Map<R, V> {
val destination = LinkedHashMap<R, V>()
for (element in this) {
@@ -290,6 +324,15 @@ object CollectionUtils {
return destination
}
+ inline fun <T, C : Number, D : Number> Iterable<T>.sumOfPair(selector: (T) -> Pair<C, D>): Pair<Double, Double> {
+ var sum = Pair(0.0, 0.0)
+ for (element in this) {
+ val add = selector(element)
+ sum = sum.first + add.first.toDouble() to sum.second + add.second.toDouble()
+ }
+ return sum
+ }
+
inline fun <T, R> Iterable<T>.zipWithNext3(transform: (a: T, b: T, c: T) -> R): List<R> {
val iterator = iterator()
if (!iterator.hasNext()) return emptyList()
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/GuiRenderUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/GuiRenderUtils.kt
index e68af00ca..403484fcd 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/GuiRenderUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/GuiRenderUtils.kt
@@ -3,6 +3,10 @@ package at.hannibal2.skyhanni.utils
import at.hannibal2.skyhanni.config.features.skillprogress.SkillProgressBarConfig
import at.hannibal2.skyhanni.features.chroma.ChromaShaderManager
import at.hannibal2.skyhanni.features.chroma.ChromaType
+import at.hannibal2.skyhanni.utils.LorenzUtils.round
+import at.hannibal2.skyhanni.utils.NumberUtil.fractionOf
+import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment
+import at.hannibal2.skyhanni.utils.renderables.Renderable
import io.github.moulberry.notenoughupdates.util.Utils
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.FontRenderer
@@ -17,11 +21,11 @@ import java.awt.Color
import java.text.DecimalFormat
import kotlin.math.ceil
import kotlin.math.min
-import kotlin.math.roundToInt
/**
* Some functions taken from NotEnoughUpdates
*/
+// TODO cleanup of redundant functions
object GuiRenderUtils {
fun drawStringCentered(str: String?, fr: FontRenderer, x: Float, y: Float, shadow: Boolean, colour: Int) {
@@ -71,12 +75,7 @@ object GuiRenderUtils {
fun drawStringCentered(str: String?, x: Int, y: Int) {
drawStringCentered(
- str,
- Minecraft.getMinecraft().fontRendererObj,
- x.toFloat(),
- y.toFloat(),
- true,
- 0xffffff
+ str, Minecraft.getMinecraft().fontRendererObj, x.toFloat(), y.toFloat(), true, 0xffffff
)
}
@@ -126,30 +125,33 @@ object GuiRenderUtils {
if (tooltipY + tooltipHeight + 6 > screenHeight) tooltipY = screenHeight - tooltipHeight - 6
// main background
GuiScreen.drawRect(
- tooltipX - 3, tooltipY - 3,
- tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, -0xfeffff0
+ tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, -0xfeffff0
)
// borders
GuiScreen.drawRect(
- tooltipX - 3, tooltipY - 3 + 1,
- tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColor
+ tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColor
)
GuiScreen.drawRect(
- tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1,
- tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColor
+ tooltipX + tooltipTextWidth + 2,
+ tooltipY - 3 + 1,
+ tooltipX + tooltipTextWidth + 3,
+ tooltipY + tooltipHeight + 3 - 1,
+ borderColor
)
GuiScreen.drawRect(
- tooltipX - 3, tooltipY - 3,
- tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColor
+ tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColor
)
GuiScreen.drawRect(
- tooltipX - 3, tooltipY + tooltipHeight + 2,
- tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, borderColor
+ tooltipX - 3,
+ tooltipY + tooltipHeight + 2,
+ tooltipX + tooltipTextWidth + 3,
+ tooltipY + tooltipHeight + 3,
+ borderColor
)
GlStateManager.translate(0f, 0f, -100f)
GlStateManager.disableDepth()
@@ -175,109 +177,38 @@ object GuiRenderUtils {
fun isPointInRect(x: Int, y: Int, left: Int, top: Int, width: Int, height: Int) =
left <= x && x < left + width && top <= y && y < top + height
- fun drawProgressBar(x: Int, y: Int, barWidth: Int, progress: Float) {
- GuiScreen.drawRect(x, y, x + barWidth, y + 6, 0xFF43464B.toInt())
- val width = barWidth * progress
- GuiScreen.drawRect(x + 1, y + 1, (x + width).toInt() + 1, y + 5, 0xFF00FF00.toInt())
- if (progress != 1f) GuiScreen.drawRect(
- (x + width).toInt() + 1,
- y + 1,
- x + barWidth - 1,
- y + 5,
- 0xFF013220.toInt()
- )
- }
-
- fun renderItemAndTip(
- list: MutableList<String>,
- item: ItemStack?,
- x: Int,
- y: Int,
- mouseX: Int,
- mouseY: Int,
- color: Int = 0xFF43464B.toInt(),
- ) {
- GuiScreen.drawRect(x, y, x + 16, y + 16, color)
- if (item != null) {
- renderItemStack(item, x, y)
- if (isPointInRect(mouseX, mouseY, x, y, 16, 16)) {
- val tt: List<String> = item.getTooltip(Minecraft.getMinecraft().thePlayer, false)
- list.addAll(tt)
- }
- }
- }
-
- fun renderItemAndTip(
- list: MutableList<String>,
- item: ItemStack?,
- x: Float,
- y: Float,
- mouseX: Float,
- mouseY: Float,
- color: Int = 0xFF43464B.toInt(),
- ) {
- renderItemAndTip(list, item, x.toInt(), y.toInt(), mouseX.toInt(), mouseY.toInt(), color)
- }
-
- // assuming 70% font size
- fun drawFarmingBar(
+ fun getFarmingBar(
label: String,
tooltip: String,
currentValue: Number,
maxValue: Number,
- xPos: Int,
- yPos: Int,
width: Int,
- mouseX: Int,
- mouseY: Int,
- output: MutableList<String>,
textScale: Float = .7f,
- ) {
- var currentVal = currentValue.toDouble()
- currentVal = if (currentVal < 0) 0.0 else currentVal
-
- var barProgress = currentVal / maxValue.toFloat()
- if (maxValue == 0) barProgress = 1.0
- barProgress = when {
- barProgress > 1 -> 1.0
- barProgress < 0 -> 0.0
- else -> barProgress
- }
-
- val filledWidth = (width * barProgress).toInt()
- val current = DecimalFormat("0.##").format(currentVal)
- val progressPercentage = (barProgress * 10000).roundToInt() / 100
- val inverseScale = 1 / textScale
- val textWidth: Int = Minecraft.getMinecraft().fontRendererObj.getStringWidth("$progressPercentage%")
- val barColor = barColorGradient(barProgress)
-
- GlStateManager.scale(textScale, textScale, 1f)
- drawString(label, xPos * inverseScale, yPos * inverseScale)
- drawString(
- "§2$current / ${DecimalFormat("0.##").format(maxValue)}☘",
- xPos * inverseScale,
- (yPos + 8) * inverseScale
- )
- drawString(
- "§2$progressPercentage%",
- (xPos + width - textWidth * textScale) * inverseScale,
- (yPos + 8) * inverseScale
- )
- GlStateManager.scale(inverseScale, inverseScale, 1f)
-
- GuiScreen.drawRect(xPos, yPos + 16, xPos + width, yPos + 20, 0xFF43464B.toInt())
- GuiScreen.drawRect(xPos + 1, yPos + 17, xPos + width - 1, yPos + 19, barColor.darkenColor())
- GuiScreen.drawRect(
- xPos + 1, yPos + 17,
- if (filledWidth < 2) xPos + 1 else xPos + filledWidth - 1, yPos + 19, barColor
- )
-
- if (tooltip != "" && isPointInRect(mouseX, mouseY, xPos - 2, yPos - 2, width + 4, 20 + 4)) {
- val split = tooltip.split("\n")
- for (line in split) {
- output.add(line)
- }
- }
+ ): Renderable {
+ val current = currentValue.toDouble().coerceAtLeast(0.0)
+ val percent = current.fractionOf(maxValue)
+ val scale = textScale.toDouble()
+ return Renderable.hoverTips(Renderable.verticalContainer(
+ listOf(
+ Renderable.string(label, scale = scale),
+ Renderable.fixedSizeLine(
+ listOf(
+ Renderable.string(
+ "§2${DecimalFormat("0.##").format(current)} / ${
+ DecimalFormat(
+ "0.##"
+ ).format(maxValue)
+ }☘", scale = scale, horizontalAlign = HorizontalAlignment.LEFT
+ ),
+ Renderable.string(
+ "§2${(percent * 100).round(1)}%",
+ scale = scale,
+ horizontalAlign = HorizontalAlignment.RIGHT
+ ),
+ ), width
+ ), Renderable.progressBar(percent, width = width)
+ )
+ ), tooltip.split('\n').map { Renderable.string(it) })
}
private fun barColorGradient(double: Double): Int {
@@ -293,8 +224,11 @@ object GuiRenderUtils {
fun drawScaledRec(left: Int, top: Int, right: Int, bottom: Int, colour: Int, inverseScale: Float) {
GuiScreen.drawRect(
- (left * inverseScale).toInt(), (top * inverseScale).toInt(),
- (right * inverseScale).toInt(), (bottom * inverseScale).toInt(), colour
+ (left * inverseScale).toInt(),
+ (top * inverseScale).toInt(),
+ (right * inverseScale).toInt(),
+ (bottom * inverseScale).toInt(),
+ colour
)
}
@@ -339,15 +273,7 @@ object GuiRenderUtils {
Utils.drawTexturedRect(x, y, w_2.toFloat(), height, 0f, w_2 / xSize, vMinEmpty, vMaxEmpty, GL11.GL_NEAREST)
Utils.drawTexturedRect(
- x + w_2,
- y,
- w_2.toFloat(),
- height,
- 1 - w_2 / xSize,
- 1f,
- vMinEmpty,
- vMaxEmpty,
- GL11.GL_NEAREST
+ x + w_2, y, w_2.toFloat(), height, 1 - w_2 / xSize, 1f, vMinEmpty, vMaxEmpty, GL11.GL_NEAREST
)
if (useChroma) {
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt
index 297a40585..cd75e9cf4 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/NEUItems.kt
@@ -217,9 +217,14 @@ object NEUItems {
const val itemFontSize = 2.0 / 3.0
- fun ItemStack.renderOnScreen(x: Float, y: Float, scaleMultiplier: Double = itemFontSize) {
+ fun ItemStack.renderOnScreen(
+ x: Float,
+ y: Float,
+ scaleMultiplier: Double = itemFontSize,
+ rescaleSkulls: Boolean = true
+ ) {
val item = checkBlinkItem()
- val isSkull = item.item === Items.skull
+ val isSkull = rescaleSkulls && item.item === Items.skull
val baseScale = (if (isSkull) 4f / 3f else 1f)
val finalScale = baseScale * scaleMultiplier
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideGUI.kt b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideGUI.kt
new file mode 100644
index 000000000..944a3201a
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideGUI.kt
@@ -0,0 +1,121 @@
+package at.hannibal2.skyhanni.utils.guide
+
+import at.hannibal2.skyhanni.test.command.ErrorManager
+import at.hannibal2.skyhanni.utils.RenderUtils
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXYAligned
+import net.minecraft.client.gui.GuiScreen
+import net.minecraft.client.renderer.GlStateManager
+import net.minecraft.item.ItemStack
+
+const val selectedColor = 0x50000000
+const val notSelectedColor = 0x50303030
+const val tabSpacing = 5
+const val tabShortSide = 25
+const val tabLongSide = 28
+
+abstract class GuideGUI<pageEnum : Enum<*>>(defaultScreen: pageEnum) : GuiScreen() {
+
+ abstract val sizeX: Int
+ abstract val sizeY: Int
+ lateinit var pageList: Map<pageEnum, GuidePage>
+ lateinit var horizontalTabs: List<GuideTab>
+ lateinit var verticalTabs: List<GuideTab>
+ protected var currentPage: pageEnum = defaultScreen
+ set(value) {
+ pageList[field]?.onLeave()
+ pageList[value]?.onEnter()
+ field = value
+ }
+
+ val lastVerticalTabWrapper = object : tabWrapper {
+ override var tab: GuideTab? = null
+ }
+ val lastHorizontalTabWrapper = object : tabWrapper {
+ override var tab: GuideTab? = null
+ }
+
+ fun hTab(item: ItemStack, tip: Renderable, onClick: (GuideTab) -> Unit) =
+ GuideTab(item, tip, false, lastHorizontalTabWrapper, onClick)
+
+ fun vTab(item: ItemStack, tip: Renderable, onClick: (GuideTab) -> Unit) =
+ GuideTab(item, tip, true, lastVerticalTabWrapper, onClick)
+
+ interface tabWrapper {
+ var tab: GuideTab?
+ }
+
+ fun refreshPage() {
+ pageList[currentPage]?.refresh()
+ }
+
+ private fun renderHorizontalTabs() {
+ var offset = Pair(tabSpacing.toFloat() * 3f, -tabLongSide.toFloat())
+ GlStateManager.translate(offset.first, offset.second, 0f)
+ for (tab in horizontalTabs) {
+ tab.render(offset.first.toInt(), offset.second.toInt())
+ val xShift = (tabShortSide + tabSpacing).toFloat()
+ offset = offset.first + xShift to offset.second
+ GlStateManager.translate(xShift, 0f, 0f)
+ }
+ GlStateManager.translate(-offset.first, -offset.second, 0f)
+ }
+
+ private fun renderVerticalTabs() {
+ var offset = Pair(-tabLongSide.toFloat(), tabSpacing.toFloat() * 3f)
+ GlStateManager.translate(offset.first, offset.second, 0f)
+ for (tab in verticalTabs) {
+ tab.render(offset.first.toInt(), offset.second.toInt())
+ val yShift = (tabShortSide + tabSpacing).toFloat()
+ offset = offset.first to offset.second + yShift
+ GlStateManager.translate(0f, yShift, 0f)
+ }
+ GlStateManager.translate(-offset.first, -offset.second, 0f)
+ }
+
+ override fun drawScreen(mouseX: Int, mouseY: Int, partialTicks: Float) = try {
+ super.drawScreen(mouseX, mouseY, partialTicks)
+ drawDefaultBackground()
+ val guiLeft = (width - sizeX) / 2
+ val guiTop = (height - sizeY) / 2
+
+ /*
+ val mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth
+ val mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1
+ */
+
+ val relativeMouseX = mouseX - guiLeft
+ val relativeMouseY = mouseY - guiTop
+
+ GlStateManager.pushMatrix()
+ GlStateManager.translate(guiLeft.toFloat(), guiTop.toFloat(), 0f)
+ drawRect(0, 0, sizeX, sizeY, 0x50000000)
+
+ Renderable.withMousePosition(relativeMouseX, relativeMouseY) {
+ renderHorizontalTabs()
+ renderVerticalTabs()
+
+ Renderable.string(
+ "§7SkyHanni ",
+ horizontalAlign = RenderUtils.HorizontalAlignment.RIGHT,
+ verticalAlign = RenderUtils.VerticalAlignment.BOTTOM
+ ).renderXYAligned(0, 0, sizeX, sizeY)
+
+ val page = pageList[currentPage]
+ page?.drawPage(relativeMouseX, relativeMouseY)
+
+ GlStateManager.translate(-guiLeft.toFloat(), -guiTop.toFloat(), 0f)
+ }
+
+ GlStateManager.popMatrix()
+
+ } catch (e: Exception) {
+ GlStateManager.popMatrix()
+ ErrorManager.logErrorWithData(
+ e, "Something broke in GuideGUI",
+ "Guide" to this.javaClass.typeName,
+ "Page" to currentPage.name
+ )
+ }
+}
+
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/guide/GuidePage.kt b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuidePage.kt
new file mode 100644
index 000000000..a563a531c
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuidePage.kt
@@ -0,0 +1,15 @@
+package at.hannibal2.skyhanni.utils.guide
+
+abstract class GuidePage {
+ abstract fun drawPage(mouseX: Int, mouseY: Int)
+
+ abstract fun onEnter()
+
+ abstract fun onLeave()
+
+ fun refresh() {
+ onLeave()
+ onEnter()
+ }
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideRenderablePage.kt b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideRenderablePage.kt
new file mode 100644
index 000000000..ce68a4afe
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideRenderablePage.kt
@@ -0,0 +1,23 @@
+package at.hannibal2.skyhanni.utils.guide
+
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import net.minecraft.client.renderer.GlStateManager
+
+abstract class GuideRenderablePage(
+ val paddingX: Int = 0,
+ val paddingY: Int = 0
+) : GuidePage() {
+
+ protected var renderable: Renderable? = null
+
+ final override fun drawPage(mouseX: Int, mouseY: Int) {
+ GlStateManager.translate(paddingX.toFloat(), paddingY.toFloat(), 0f)
+ renderable?.render(paddingX, paddingY)
+ GlStateManager.translate(-paddingX.toFloat(), -paddingY.toFloat(), 0f)
+ }
+
+ override fun onLeave() {
+ renderable = null
+ }
+
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideScrollPage.kt b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideScrollPage.kt
new file mode 100644
index 000000000..97cf68442
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideScrollPage.kt
@@ -0,0 +1,31 @@
+package at.hannibal2.skyhanni.utils.guide
+
+import at.hannibal2.skyhanni.utils.CollectionUtils.tableStretchXPadding
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.renderables.ScrollValue
+
+abstract class GuideScrollPage(
+ val sizeX: Int,
+ val sizeY: Int,
+ paddingX: Int = 0,
+ paddingY: Int = 0,
+ val marginY: Int = 5,
+ val velocity: Double = 3.0,
+ val hasHeader: Boolean = true,
+) : GuideRenderablePage(paddingX, paddingY) {
+
+ private val scroll = ScrollValue()
+
+ fun update(content: List<List<Renderable>>) {
+ renderable = Renderable.scrollTable(
+ content = content,
+ height = sizeY - paddingY * 2,
+ scrollValue = scroll,
+ velocity = velocity,
+ xPadding = content.tableStretchXPadding(sizeX - paddingX * 2),
+ yPadding = marginY,
+ hasHeader = hasHeader,
+ button = 0
+ )
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTab.kt b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTab.kt
new file mode 100644
index 000000000..acc69c8cc
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTab.kt
@@ -0,0 +1,67 @@
+package at.hannibal2.skyhanni.utils.guide
+
+import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment
+import at.hannibal2.skyhanni.utils.RenderUtils.VerticalAlignment
+import at.hannibal2.skyhanni.utils.SoundUtils
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXYAligned
+import net.minecraft.client.gui.Gui
+import net.minecraft.item.ItemStack
+
+class GuideTab(
+ val item: ItemStack,
+ val tip: Renderable,
+ val isVertical: Boolean = false,
+ var lastTab: GuideGUI.tabWrapper,
+ val onClick: (GuideTab) -> Unit
+) {
+
+ fun fakeClick() = click()
+
+ private fun click() {
+ onClick.invoke(this)
+ this.select()
+ if (lastTab.tab != this) {
+ lastTab.tab?.unSelect()
+ lastTab.tab = this
+ }
+ }
+
+ fun select() {
+ selectColor = selectedColor
+ }
+
+ fun unSelect() {
+ selectColor = notSelectedColor
+ }
+
+ fun isSelected() = selectColor == selectedColor
+
+ val width = if (isVertical) tabLongSide else tabShortSide
+ val height = if (isVertical) tabShortSide else tabLongSide
+
+ private var selectColor = notSelectedColor
+
+ private val renderable = Renderable.clickAndHover(object : Renderable {
+ override val width = this@GuideTab.width
+ override val height = this@GuideTab.height
+ override val horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT
+ override val verticalAlign: VerticalAlignment = VerticalAlignment.TOP
+
+ val itemRender = Renderable.itemStack(
+ item, 1.0, horizontalAlign = HorizontalAlignment.CENTER, verticalAlign = VerticalAlignment.CENTER
+ )
+
+ override fun render(posX: Int, posY: Int) {
+ Gui.drawRect(0, 0, width, height, selectColor)
+ itemRender.renderXYAligned(posX, posY, width, height)
+ }
+ }, listOf(tip), onClick = {
+ click()
+ SoundUtils.playClickSound()
+ })
+
+ fun render(posX: Int, posY: Int) {
+ renderable.render(posX, posY)
+ }
+}
diff --git a/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTablePage.kt b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTablePage.kt
new file mode 100644
index 000000000..85dd5bdda
--- /dev/null
+++ b/src/main/java/at/hannibal2/skyhanni/utils/guide/GuideTablePage.kt
@@ -0,0 +1,33 @@
+package at.hannibal2.skyhanni.utils.guide
+
+import at.hannibal2.skyhanni.utils.CollectionUtils.tableStretchXPadding
+import at.hannibal2.skyhanni.utils.CollectionUtils.tableStretchYPadding
+import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment
+import at.hannibal2.skyhanni.utils.renderables.Renderable
+
+abstract class GuideTablePage(
+ val sizeX: Int,
+ val sizeY: Int,
+ paddingX: Int = 0,
+ paddingY: Int = 0,
+ val footerSpacing: Int = 2
+) : GuideRenderablePage(paddingX, paddingY) {
+
+ fun update(
+ content: List<List<Renderable>>,
+ footer: List<Renderable> = emptyList()
+ ) {
+ val ySpace = (content + listOf(footer)).tableStretchYPadding(sizeY - paddingY * 2)
+ renderable =
+ Renderable.verticalContainer(
+ listOf(
+ Renderable.table(
+ content,
+ xPadding = content.tableStretchXPadding(sizeX - paddingX * 2),
+ yPadding = ySpace
+ ),
+ Renderable.horizontalContainer(footer, footerSpacing, horizontalAlign = HorizontalAlignment.CENTER)
+ ), spacing = ySpace
+ )
+ }
+}
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 88b291844..070d7db10 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt
@@ -19,6 +19,7 @@ import at.hannibal2.skyhanni.utils.NEUItems.renderOnScreen
import at.hannibal2.skyhanni.utils.RenderUtils
import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment
import at.hannibal2.skyhanni.utils.RenderUtils.VerticalAlignment
+import at.hannibal2.skyhanni.utils.guide.GuideGUI
import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.calculateTableXOffsets
import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.calculateTableYOffsets
import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXAligned
@@ -230,18 +231,20 @@ interface Renderable {
}
private fun shouldAllowLink(debug: Boolean = false, bypassChecks: Boolean): Boolean {
- val isGuiScreen = Minecraft.getMinecraft().currentScreen != null
+ val guiScreen = Minecraft.getMinecraft().currentScreen
+
+ val isGuiScreen = guiScreen != null
if (bypassChecks) {
return isGuiScreen
}
val inMenu = Minecraft.getMinecraft().currentScreen !is GuiIngameMenu
- val isGuiPositionEditor = Minecraft.getMinecraft().currentScreen !is GuiPositionEditor
- val isNotInSignAndOnSlot = if (Minecraft.getMinecraft().currentScreen !is GuiEditSign) {
+ val isGuiPositionEditor = guiScreen !is GuiPositionEditor
+ val isNotInSignAndOnSlot = if (guiScreen !is GuiEditSign && guiScreen !is GuideGUI<*>) {
ToolTipData.lastSlot == null || GuiData.preDrawEventCanceled
} else true
- val isConfigScreen = Minecraft.getMinecraft().currentScreen !is GuiScreenElementWrapper
+ val isConfigScreen = guiScreen !is GuiScreenElementWrapper
- val openGui = Minecraft.getMinecraft().currentScreen?.javaClass?.name ?: "none"
+ val openGui = guiScreen?.javaClass?.name ?: "none"
val isInNeuPv = openGui == "io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer"
val neuFocus = NEUItems.neuHasFocus()
val isInSkyTilsPv = openGui == "gg.skytils.skytilsmod.gui.profile.ProfileGui"
@@ -313,20 +316,45 @@ interface Renderable {
}
}
+ fun itemStackWithTip(
+ item: ItemStack,
+ scale: Double = NEUItems.itemFontSize,
+ xSpacing: Int = 2,
+ ySpacing: Int = 0,
+ rescaleSkulls: Boolean = true,
+ horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
+ verticalAlign: VerticalAlignment = VerticalAlignment.TOP,
+ ) =
+ hoverTips(
+ itemStack(
+ item,
+ scale,
+ xSpacing,
+ ySpacing,
+ rescaleSkulls,
+ horizontalAlign = horizontalAlign,
+ verticalAlign = verticalAlign
+ ),
+ item.getTooltip(Minecraft.getMinecraft().thePlayer, false),
+ stack = item
+ )
+
fun itemStack(
item: ItemStack,
scale: Double = NEUItems.itemFontSize,
xSpacing: Int = 2,
+ ySpacing: Int = 1,
+ rescaleSkulls: Boolean = true,
horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
verticalAlign: VerticalAlignment = VerticalAlignment.CENTER,
) = object : Renderable {
- override val width = (15.5 * scale + 1.5).toInt() + xSpacing
- override val height = (15.5 * scale + 1.5).toInt()
+ override val width = (15.5 * scale + 0.5).toInt() + xSpacing
+ override val height = (15.5 * scale + 0.5).toInt() + ySpacing
override val horizontalAlign = horizontalAlign
override val verticalAlign = verticalAlign
override fun render(posX: Int, posY: Int) {
- item.renderOnScreen(xSpacing / 2.0f, 0F, scaleMultiplier = scale)
+ item.renderOnScreen(xSpacing / 2.0f, 0F, scaleMultiplier = scale, rescaleSkulls)
}
}
@@ -379,7 +407,7 @@ interface Renderable {
scale: Double = 1.0,
color: Color = Color.WHITE,
horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
- verticalAlign: VerticalAlignment = VerticalAlignment.TOP,
+ verticalAlign: VerticalAlignment = VerticalAlignment.CENTER,
) = object : Renderable {
val list by lazy {
@@ -390,9 +418,9 @@ interface Renderable {
override val width by lazy {
if (list.size == 1) {
- (Minecraft.getMinecraft().fontRendererObj.getStringWidth(text) / scale).toInt() + 1
+ (Minecraft.getMinecraft().fontRendererObj.getStringWidth(text) * scale).toInt() + 1
} else {
- (width / scale).toInt() + 1
+ width
}
}
@@ -431,6 +459,7 @@ interface Renderable {
content: List<List<Renderable?>>,
xPadding: Int = 1,
yPadding: Int = 0,
+ useEmptySpace: Boolean = false,
horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
verticalAlign: VerticalAlignment = VerticalAlignment.TOP,
) = object : Renderable {
@@ -442,6 +471,9 @@ interface Renderable {
override val width = xOffsets.last() - xPadding
override val height = yOffsets.last() - yPadding
+ val emptySpaceX = if (useEmptySpace) 0 else xPadding
+ val emptySpaceY = if (useEmptySpace) 0 else yPadding
+
override fun render(posX: Int, posY: Int) {
content.forEachIndexed { rowIndex, row ->
row.forEachIndexed { index, renderable ->
@@ -450,8 +482,8 @@ interface Renderable {
renderable?.renderXYAligned(
posX + xOffsets[index],
posY + yOffsets[rowIndex],
- xOffsets[index + 1] - xOffsets[index],
- yOffsets[rowIndex + 1] - yOffsets[rowIndex]
+ xOffsets[index + 1] - xOffsets[index] - emptySpaceX,
+ yOffsets[rowIndex + 1] - yOffsets[rowIndex] - emptySpaceY
)
GlStateManager.popMatrix()
}
@@ -557,7 +589,52 @@ interface Renderable {
override val horizontalAlign = horizontalAlign
override val verticalAlign = verticalAlign
override fun render(posX: Int, posY: Int) {
- render.renderXAligned(0, 0, width)
+ render.renderXAligned(posX, posY, width)
+ }
+ }
+
+ fun fixedSizeLine(
+ content: List<Renderable>,
+ width: Int,
+ horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
+ verticalAlign: VerticalAlignment = VerticalAlignment.TOP,
+ ) = object : Renderable {
+ val render = content
+
+ override val width = width
+ override val height = render.maxOfOrNull { it.height } ?: 0
+ override val horizontalAlign = horizontalAlign
+ override val verticalAlign = verticalAlign
+
+ val emptySpace = width - render.sumOf { it.width }
+ val spacing = emptySpace / render.size
+
+ override fun render(posX: Int, posY: Int) {
+ var xOffset = posX
+ render.forEach {
+ val x = it.width + spacing
+ it.renderXYAligned(xOffset, posY, x, height)
+ xOffset += x
+ GlStateManager.translate(x.toFloat(), 0f, 0f)
+ }
+ GlStateManager.translate(-(xOffset - posX).toFloat(), 0f, 0f)
+ }
+ }
+
+ fun fixedSizeCollum(
+ content: Renderable,
+ height: Int,
+ horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT,
+ verticalAlign: VerticalAlignment = VerticalAlignment.TOP,
+ ) = object : Renderable {
+ val render = content
+
+ override val width = render.width
+ override val height = height
+ override val horizontalAlign = horizontalAlign
+ override val verticalAlign = verticalAlign
+ override fun render(posX: Int, posY: Int) {
+ render.renderYAligned(posX, posY, height)
}
}
@@ -601,7 +678,7 @@ interface Renderable {
override fun render(posX: Int, posY: Int) {
var yOffset = posY
renderables.forEach {
- it.renderXAligned(yOffset, posX, width)
+ it.renderXAligned(posX, yOffset, width)
yOffset += it.height + spacing
GlStateManager.translate(0f, (it.height + spacing).toFloat(), 0f)
}
@@ -722,7 +799,15 @@ interface Renderable {
yOffsets.indexOfFirst { it >= scroll.asInt() }..<(yOffsets.indexOfFirst { it >= end }
.takeIf { it > 0 }
?: yOffsets.size) - 1
- for (rowIndex in range) {
+
+ val range2 =
+ if (range.last + 3 <= yOffsets.size && yOffsets[range.last + 2] - yOffsets[range.first] <= height - renderY) {
+ range.first..range.last() + 1
+ } else {
+ range
+ }
+
+ for (rowIndex in range2) {
content[rowIndex].forEachIndexed { index, renderable ->
GlStateManager.translate(xOffsets[index].toFloat(), 0f, 0f)
renderable?.renderXYAligned(
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 e1f93574e..cf81fc9ff 100644
--- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt
+++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/RenderableUtils.kt
@@ -13,22 +13,25 @@ internal object RenderableUtils {
buildList {
add(0)
while (true) {
- buffer += content.map { it.getOrNull(index) }.takeIf { it.any { it != null } }?.maxOf {
+ buffer += content.map { it.getOrNull(index) }.takeIf { it.any { it != null } }?.maxOfOrNull {
it?.width ?: 0
}?.let { it + xPadding } ?: break
add(buffer)
index++
}
+ if (this.size == 1) {
+ add(xPadding)
+ }
}
}
/** Calculates the absolute y position of the rows in a table*/
fun calculateTableYOffsets(content: List<List<Renderable?>>, yPadding: Int) = run {
var buffer = 0
- listOf(0) + content.map { row ->
- buffer += row.maxOf { it?.height ?: 0 } + yPadding
+ listOf(0) + (content.takeIf { it.isNotEmpty() }?.map { row ->
+ buffer += (row.maxOfOrNull { it?.height ?: 0 } ?: 0) + yPadding
buffer
- }
+ } ?: listOf(yPadding))
}
private fun calculateAlignmentXOffset(renderable: Renderable, xSpace: Int) = when (renderable.horizontalAlign) {