diff options
author | Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com> | 2024-06-05 15:39:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-05 15:39:55 +0200 |
commit | 5a04ad230cc4fb94884b34f795124d3b65af07ea (patch) | |
tree | cace8dcaad1c989be42a52bff4a6da233642279f /src/main/java/at/hannibal2/skyhanni/utils | |
parent | eb4ab6eaafa17581df58a53fb4111fa96933d230 (diff) | |
download | skyhanni-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')
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) { |