From e2c7ca7243aba4a00b104f7614e20e4cb5f573ad Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Wed, 4 Dec 2024 20:11:00 -0500 Subject: [PATCH] Improvement: Cake Tracker Scrollable and AH Tips (#2939) --- .../features/inventory/CakeTrackerConfig.java | 13 ++- .../inventory/caketracker/CakeTracker.kt | 80 +++++++++---------- .../skyhanni/utils/renderables/Renderable.kt | 32 +++++++- 3 files changed, 75 insertions(+), 50 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/CakeTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/CakeTrackerConfig.java index 67bd1d7d2b58..deb29b7c699b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/CakeTrackerConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/CakeTrackerConfig.java @@ -23,9 +23,8 @@ public class CakeTrackerConfig { @Expose @ConfigOption( name = "Note", - desc = "§cNote7:" + - "\nThis feature is not compatible with the NEU Storage Overlay." + - "\nBackpacks/Ender Chest will not be scanned correctly with it enabled." + desc = "This feature is not compatible with the NEU Storage Overlay." + + "Backpacks/Ender Chest will not be scanned correctly with it enabled." ) @ConfigEditorInfoText public boolean incompatibleNote = false; @@ -73,9 +72,9 @@ public enum CakeTrackerDisplayOrderType { @Expose @ConfigOption( - name = "Maximum Rows", - desc = "The maximum number of rows to display in the tracker, before a cutoff is imposed." + name = "Max Height", + desc = "Maximum height of the tracker." ) - @ConfigEditorSlider(minValue = 5, maxValue = 40, minStep = 1) - public Property maxDisplayRows = Property.of(20); + @ConfigEditorSlider(minValue = 50, maxValue = 500, minStep = 10) + public Property maxHeight = Property.of(250F); } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/caketracker/CakeTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/caketracker/CakeTracker.kt index 40368d49a48c..74a018db80ed 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/caketracker/CakeTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/caketracker/CakeTracker.kt @@ -19,7 +19,6 @@ import at.hannibal2.skyhanni.features.inventory.patternGroup import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ConditionalUtils -import at.hannibal2.skyhanni.utils.ConfigUtils.jumpToEditor import at.hannibal2.skyhanni.utils.HypixelCommands import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.InventoryUtils.getUpperItems @@ -112,6 +111,7 @@ object CakeTracker { private val storage get() = ProfileStorageData.profileSpecific?.cakeData private val config get() = SkyHanniMod.feature.inventory.cakeTracker + private val maxTrackerHeight: Float get() = config.maxHeight.get() private var currentYear = 0 private var inCakeInventory = false @@ -170,7 +170,7 @@ object CakeTracker { @SubscribeEvent fun onConfigLoad(event: ConfigLoadEvent) { - ConditionalUtils.onToggle(config.maxDisplayRows) { + ConditionalUtils.onToggle(config.maxHeight) { lastKnownCakeDataHash = 0 } } @@ -299,25 +299,31 @@ object CakeTracker { fun getRenderable(displayType: DisplayType): Renderable { val colorCode = if (displayType == DisplayType.OWNED_CAKES) "§a" else "§c" - val baseRenderable = getHoverable(colorCode) - return if (displayType == DisplayType.MISSING_CAKES) Renderable.link( + val baseRenderable = getHoverable(displayType, colorCode) + return if (displayType == DisplayType.MISSING_CAKES && config.priceOnHover) Renderable.link( baseRenderable, { HypixelCommands.auctionSearch("New Year Cake (Year $start)") }, ) else baseRenderable } - fun getHoverable(colorCode: String): Renderable { + fun getHoverable(displayType: DisplayType, colorCode: String): Renderable { val displayString = if (isSingular) "§fYear $colorCode$start" else "§fYears $colorCode$start§f-$colorCode$end" return if (!config.priceOnHover) Renderable.string(displayString) - else Renderable.hoverTips(displayString, getPriceHoverTooltip(colorCode)) + else Renderable.hoverTips( + displayString, + getPriceHoverTooltip(displayType, colorCode) + ) } - fun getPriceHoverTooltip(colorCode: String): List { + fun getPriceHoverTooltip(displayType: DisplayType, colorCode: String): List { return if (isSingular) { - listOf("${colorCode}Year $start§7: ${getCakePriceString(start)}") + listOf( + "${colorCode}Year $start§7: ${getCakePriceString(start)}", + "§eClick to search auction house", + ) } else buildList { val largerNumber = if (start > end) start else end val smallerNumber = if (start < end) start else end @@ -330,6 +336,9 @@ object CakeTracker { if (rangeLength >= 5) add("§7§o... and ${rangeLength - 5} more") add("") add("§aTotal§7: §6${numericalRange.sumOf(::getCakePrice).addSeparators()}") + if (displayType == DisplayType.MISSING_CAKES) { + add("§eClick to search auction house") + } } } } @@ -430,59 +439,46 @@ object CakeTracker { val colorCode = if (config.displayType == DisplayType.OWNED_CAKES) "§c" else "§a" val verbiage = if (config.displayType == DisplayType.OWNED_CAKES) "missing" else "owned" add(Renderable.string("$colorCode§lAll cakes $verbiage!")) - } else addCakeRanges(cakeList, config.displayOrderType, config.displayType) + } else add( + Renderable.scrollList( + getCakeRanges(cakeList, config.displayOrderType, config.displayType), + height = maxTrackerHeight.toInt() + 2, // +2 to account for tips + velocity = 20.0, + showScrollableTipsInList = true + ) + ) } - private fun MutableList.addCakeRanges( + private fun getCakeRanges( cakeList: Set, orderType: DisplayOrder, displayType: DisplayType, - ) { + ): List = buildList { val sortedCakes = when (orderType) { DisplayOrder.OLDEST_FIRST -> cakeList.sorted() DisplayOrder.NEWEST_FIRST -> cakeList.sortedDescending() } - // Combine consecutive years into ranges - // + 3 is to account for the header and selector boxes - val maxDisplayRows = config.maxDisplayRows.get() + 3 var start = sortedCakes.first() var end = start - var hiddenRows = 0 for (year in sortedCakes.drop(1)) { // Skip the first item to prevent duplicate addition - if ((orderType == DisplayOrder.OLDEST_FIRST && year == end + 1) || - (orderType == DisplayOrder.NEWEST_FIRST && year == end - 1) - ) { - end = year - } else { - if (this.size < maxDisplayRows) { - val range = if (start != end) CakeRange(start, end) else CakeRange(start) - add(range.getRenderable(displayType)) - } else { - hiddenRows++ - start = year - end = start - continue - } + val oldestFirstAtEnd = orderType == DisplayOrder.OLDEST_FIRST && year == end + 1 + val newestFirstAtEnd = orderType == DisplayOrder.NEWEST_FIRST && year == end - 1 + + if (oldestFirstAtEnd || newestFirstAtEnd) end = year + else { + val range = if (start != end) CakeRange(start, end) else CakeRange(start) + add(range.getRenderable(displayType)) start = year end = start } } - if (this.size < maxDisplayRows) { - val lastRange = if (start != end) CakeRange(start, end) else CakeRange(start) - add(lastRange.getRenderable(displayType)) - } else { - hiddenRows++ - } + val lastRange = + if (start != end) CakeRange(start, end) + else CakeRange(start) - if (hiddenRows > 0) add( - Renderable.clickAndHover( - "§7§o($hiddenRows hidden rows)", - tips = listOf("§eClick to configure # of displayed rows"), - onClick = { config::maxDisplayRows.jumpToEditor() }, - ), - ) + add(lastRange.getRenderable(displayType)) } } 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 c497244796c3..56b83ae90360 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/renderables/Renderable.kt @@ -975,8 +975,12 @@ interface Renderable { bypassChecks: Boolean = false, horizontalAlign: HorizontalAlignment = HorizontalAlignment.LEFT, verticalAlign: VerticalAlignment = VerticalAlignment.TOP, + showScrollableTipsInList: Boolean = false ) = object : Renderable { - override val width = list.maxOf { it.width } + private val scrollUpTip = string("§7§oMore items above (scroll)") + private val scrollDownTip = string("§7§oMore items below (scroll)") + + override var width = list.maxOf { it.width } override val height = height override val horizontalAlign = horizontalAlign override val verticalAlign = verticalAlign @@ -1001,6 +1005,23 @@ interface Renderable { var renderY = 0 var virtualY = 0 var found = false + + // If showScrollableTipsInList is true, and we are scrolled 'down', display a tip indicating + // there are more items above + if (showScrollableTipsInList && scroll.asInt() > 0) { + width = maxOf(width, scrollUpTip.width) + scrollUpTip.renderXAligned(posX, posY, width) + GlStateManager.translate(0f, scrollUpTip.height.toFloat(), 0f) + renderY += scrollUpTip.height + virtualY += scrollUpTip.height + } + + val atScrollEnd = scroll.asInt() == virtualHeight - height + if (!atScrollEnd) { + virtualY += scrollDownTip.height + renderY += scrollDownTip.height + } + for (renderable in list) { if ((virtualY..virtualY + renderable.height) in scroll.asInt()..end) { renderable.renderXAligned(posX, posY + renderY, width) @@ -1016,6 +1037,15 @@ interface Renderable { } virtualY += renderable.height } + + // If showScrollableTipsInList is true, and we are scrolled 'up', display a tip indicating + // there are more items below + if (showScrollableTipsInList && virtualY > end) { + width = maxOf(width, scrollDownTip.width) + scrollDownTip.renderXAligned(posX, posY + height - scrollDownTip.height, width) + GlStateManager.translate(0f, scrollDownTip.height.toFloat(), 0f) + } + GlStateManager.translate(0f, -renderY.toFloat(), 0f) } }