unusable item detection logics modified
This commit is contained in:
+96
-22
@@ -83,26 +83,37 @@ local function ScanTooltipLines(bagID, slotID, itemLink)
|
|||||||
tooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
|
tooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
|
||||||
tooltip:ClearLines()
|
tooltip:ClearLines()
|
||||||
|
|
||||||
|
-- Helper to safely call SetHyperlink (can fail with "Unknown link type")
|
||||||
|
local function SafeSetHyperlink(tip, link)
|
||||||
|
if not link then return false end
|
||||||
|
-- Extract just the item:XXXX portion for SetHyperlink
|
||||||
|
local _, _, itemString = string.find(link, "|H(item:[^|]+)|h")
|
||||||
|
if itemString then
|
||||||
|
local success = pcall(function() tip:SetHyperlink(itemString) end)
|
||||||
|
return success
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- Set tooltip based on what we have
|
-- Set tooltip based on what we have
|
||||||
if bagID and slotID then
|
if bagID and slotID then
|
||||||
if bagID == -1 then
|
if bagID == -1 then
|
||||||
-- Bank main bag: use SetInventoryItem (slot 39 + slotID)
|
-- Bank main bag: SetInventoryItem doesn't work for bank slots
|
||||||
if tooltip.SetInventoryItem then
|
-- Use SetHyperlink with the item link instead
|
||||||
tooltip:SetInventoryItem("player", 39 + slotID)
|
if not SafeSetHyperlink(tooltip, itemLink) then
|
||||||
else
|
return {}
|
||||||
-- Fallback to hyperlink if SetInventoryItem not available
|
|
||||||
if itemLink then
|
|
||||||
tooltip:SetHyperlink(itemLink)
|
|
||||||
else
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
elseif bagID >= 5 and bagID <= 10 then
|
||||||
|
-- Bank bags: Try SetBagItem first, it should work for bank bags
|
||||||
|
tooltip:SetBagItem(bagID, slotID)
|
||||||
else
|
else
|
||||||
-- Regular bags and bank bags (5-11)
|
-- Regular bags (0-4): SetBagItem works reliably
|
||||||
tooltip:SetBagItem(bagID, slotID)
|
tooltip:SetBagItem(bagID, slotID)
|
||||||
end
|
end
|
||||||
elseif itemLink then
|
elseif itemLink then
|
||||||
tooltip:SetHyperlink(itemLink)
|
if not SafeSetHyperlink(tooltip, itemLink) then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
else
|
else
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
@@ -301,28 +312,84 @@ local function IsRedColor(r, g, b)
|
|||||||
return (dr < 0.15 and dg < 0.15 and db < 0.15)
|
return (dr < 0.15 and dg < 0.15 and db < 0.15)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check if red text is a legitimate requirement (not just loading state or flavor text)
|
||||||
|
-- Returns true if text appears to be an actual unmet requirement
|
||||||
|
local function IsRequirementText(text)
|
||||||
|
if not text or text == "" then return false end
|
||||||
|
local lower = string.lower(text)
|
||||||
|
|
||||||
|
-- Known requirement patterns in vanilla WoW
|
||||||
|
if string.find(lower, "requires") then return true end -- "Requires Level 60", "Requires Class:", etc.
|
||||||
|
if string.find(lower, "require") then return true end -- Alternate forms
|
||||||
|
if string.find(lower, "classes:") then return true end -- "Classes: Warrior, Paladin"
|
||||||
|
if string.find(lower, "races:") then return true end -- "Races: Dwarf, Gnome"
|
||||||
|
if string.find(lower, "level %d") then return true end -- "Level 60" (without Requires)
|
||||||
|
if string.find(lower, "skill:") then return true end -- Profession requirements
|
||||||
|
if string.find(lower, "reputation") then return true end -- Reputation requirements
|
||||||
|
if string.find(lower, "riding") then return true end -- Riding skill
|
||||||
|
if string.find(lower, "already known") then return true end -- Recipe already known
|
||||||
|
|
||||||
|
-- Class names (when shown in red, indicates class restriction)
|
||||||
|
if string.find(lower, "warrior") then return true end
|
||||||
|
if string.find(lower, "paladin") then return true end
|
||||||
|
if string.find(lower, "hunter") then return true end
|
||||||
|
if string.find(lower, "rogue") then return true end
|
||||||
|
if string.find(lower, "priest") then return true end
|
||||||
|
if string.find(lower, "shaman") then return true end
|
||||||
|
if string.find(lower, "mage") then return true end
|
||||||
|
if string.find(lower, "warlock") then return true end
|
||||||
|
if string.find(lower, "druid") then return true end
|
||||||
|
|
||||||
|
-- Race names (when shown in red, indicates race restriction)
|
||||||
|
if string.find(lower, "human") then return true end
|
||||||
|
if string.find(lower, "dwarf") then return true end
|
||||||
|
if string.find(lower, "night elf") then return true end
|
||||||
|
if string.find(lower, "gnome") then return true end
|
||||||
|
if string.find(lower, "orc") then return true end
|
||||||
|
if string.find(lower, "undead") then return true end
|
||||||
|
if string.find(lower, "tauren") then return true end
|
||||||
|
if string.find(lower, "troll") then return true end
|
||||||
|
if string.find(lower, "goblin") then return true end -- Turtle WoW
|
||||||
|
if string.find(lower, "high elf") then return true end -- Turtle WoW
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- Check if item is unusable (has red text indicating unmet requirements)
|
-- Check if item is unusable (has red text indicating unmet requirements)
|
||||||
-- Excludes durability lines (broken items show red durability)
|
-- Excludes: durability lines, item name (line 1), non-requirement text
|
||||||
local function DetectUnusable(lines)
|
local function DetectUnusable(lines)
|
||||||
for _, line in ipairs(lines) do
|
local numLines = table.getn(lines)
|
||||||
if line.r and line.g and line.b then
|
|
||||||
|
-- If tooltip has very few lines, data might not be loaded - be conservative
|
||||||
|
if numLines < 2 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Start from line 2 to skip the item name (line 1)
|
||||||
|
-- Item names can appear red when data isn't fully loaded
|
||||||
|
for i = 2, numLines do
|
||||||
|
local line = lines[i]
|
||||||
|
if line and line.r and line.g and line.b then
|
||||||
-- Check for red text (requirements not met)
|
-- Check for red text (requirements not met)
|
||||||
local isRed = IsRedColor(line.r, line.g, line.b) or
|
local isRed = IsRedColor(line.r, line.g, line.b) or
|
||||||
(line.r > 0.85 and line.g < 0.3 and line.b < 0.3)
|
(line.r > 0.85 and line.g < 0.3 and line.b < 0.3)
|
||||||
|
|
||||||
if isRed then
|
if isRed then
|
||||||
local text = line.left or ""
|
local text = line.left or ""
|
||||||
|
|
||||||
-- Ignore durability lines (broken items)
|
-- Ignore durability lines (broken items)
|
||||||
if durabilityPattern and string.find(text, durabilityPattern) then
|
if durabilityPattern and string.find(text, durabilityPattern) then
|
||||||
-- skip durability
|
-- skip durability
|
||||||
else
|
-- Only count as unusable if text looks like a requirement
|
||||||
|
elseif IsRequirementText(text) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
-- If red but not a requirement pattern, ignore it (might be flavor text or loading state)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Also check right column (some requirements appear there)
|
-- Also check right column (some requirements appear there, like "Warrior" class)
|
||||||
if line.rightR and line.rightG and line.rightB then
|
if line and line.rightR and line.rightG and line.rightB then
|
||||||
local isRed = IsRedColor(line.rightR, line.rightG, line.rightB) or
|
local isRed = IsRedColor(line.rightR, line.rightG, line.rightB) or
|
||||||
(line.rightR > 0.85 and line.rightG < 0.3 and line.rightB < 0.3)
|
(line.rightR > 0.85 and line.rightG < 0.3 and line.rightB < 0.3)
|
||||||
|
|
||||||
@@ -330,7 +397,7 @@ local function DetectUnusable(lines)
|
|||||||
local text = line.right or ""
|
local text = line.right or ""
|
||||||
if durabilityPattern and string.find(text, durabilityPattern) then
|
if durabilityPattern and string.find(text, durabilityPattern) then
|
||||||
-- skip durability
|
-- skip durability
|
||||||
else
|
elseif IsRequirementText(text) then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -369,13 +436,19 @@ function ItemDetection:GetItemProperties(itemData, bagID, slotID)
|
|||||||
|
|
||||||
-- Scan tooltip once
|
-- Scan tooltip once
|
||||||
local lines = ScanTooltipLines(bagID, slotID, itemLink)
|
local lines = ScanTooltipLines(bagID, slotID, itemLink)
|
||||||
|
local numLines = table.getn(lines)
|
||||||
|
|
||||||
-- Debug: log if tooltip scan failed
|
-- Debug: log if tooltip scan failed
|
||||||
if table.getn(lines) == 0 and addon.DEBUG then
|
if numLines == 0 and addon.DEBUG then
|
||||||
addon:Debug("ItemDetection: No tooltip lines for %s (bag=%s, slot=%s)",
|
addon:Debug("ItemDetection: No tooltip lines for %s (bag=%s, slot=%s)",
|
||||||
tostring(itemData.name or itemLink), tostring(bagID), tostring(slotID))
|
tostring(itemData.name or itemLink), tostring(bagID), tostring(slotID))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check if tooltip data appears complete
|
||||||
|
-- A proper item tooltip should have at least 2 lines (name + something)
|
||||||
|
-- If tooltip is too short, data may not be fully loaded - don't cache
|
||||||
|
local tooltipLooksComplete = (numLines >= 2)
|
||||||
|
|
||||||
-- Detect all properties
|
-- Detect all properties
|
||||||
local isPermanentEnchant = DetectPermanentEnchant(lines)
|
local isPermanentEnchant = DetectPermanentEnchant(lines)
|
||||||
local isQuestItem, isQuestStarter = DetectQuestItem(lines, itemData)
|
local isQuestItem, isQuestStarter = DetectQuestItem(lines, itemData)
|
||||||
@@ -409,8 +482,9 @@ function ItemDetection:GetItemProperties(itemData, bagID, slotID)
|
|||||||
isUnusable = isUnusable,
|
isUnusable = isUnusable,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Cache result
|
-- Only cache result if tooltip data appears complete
|
||||||
if cacheKey then
|
-- This prevents caching incorrect results from partially-loaded item data
|
||||||
|
if cacheKey and tooltipLooksComplete then
|
||||||
detectionCache[cacheKey] = result
|
detectionCache[cacheKey] = result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+86
-5
@@ -30,6 +30,68 @@ local isMerchantOpen = false -- Track whether a vendor window is currently open
|
|||||||
-- Global click catcher for clearing search focus
|
-- Global click catcher for clearing search focus
|
||||||
local clickCatcher = nil
|
local clickCatcher = nil
|
||||||
|
|
||||||
|
--=====================================================
|
||||||
|
-- Deferred Usability Tint System
|
||||||
|
-- Prevents false positives when item data isn't fully loaded on bag open
|
||||||
|
-- Uses debouncing to handle rapid open/close safely
|
||||||
|
--=====================================================
|
||||||
|
local usabilityCheckFrame = nil
|
||||||
|
local USABILITY_CHECK_DELAY = 0.25 -- Delay before re-checking usability (seconds)
|
||||||
|
|
||||||
|
-- Cancel any pending deferred usability check
|
||||||
|
local function CancelDeferredUsabilityCheck()
|
||||||
|
if usabilityCheckFrame then
|
||||||
|
usabilityCheckFrame:Hide()
|
||||||
|
usabilityCheckFrame.pending = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update usability tints on all visible item buttons
|
||||||
|
local function UpdateAllUsabilityTints()
|
||||||
|
if not Guda_BagFrame or not Guda_BagFrame:IsShown() then return end
|
||||||
|
|
||||||
|
for _, bagParent in pairs(bagParents) do
|
||||||
|
if bagParent and bagParent.itemButtons then
|
||||||
|
for button in pairs(bagParent.itemButtons) do
|
||||||
|
if button.hasItem and button:IsShown() and Guda_ItemButton_UpdateUsableTint then
|
||||||
|
Guda_ItemButton_UpdateUsableTint(button)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Schedule a deferred usability check with debouncing
|
||||||
|
local function ScheduleDeferredUsabilityCheck()
|
||||||
|
-- Create frame on first use
|
||||||
|
if not usabilityCheckFrame then
|
||||||
|
usabilityCheckFrame = CreateFrame("Frame")
|
||||||
|
usabilityCheckFrame:Hide()
|
||||||
|
usabilityCheckFrame.elapsed = 0
|
||||||
|
usabilityCheckFrame.pending = false
|
||||||
|
usabilityCheckFrame:SetScript("OnUpdate", function()
|
||||||
|
this.elapsed = this.elapsed + arg1
|
||||||
|
if this.elapsed >= USABILITY_CHECK_DELAY then
|
||||||
|
this:Hide()
|
||||||
|
this.pending = false
|
||||||
|
-- Only run if bag is still open
|
||||||
|
if Guda_BagFrame and Guda_BagFrame:IsShown() then
|
||||||
|
-- Clear detection cache and re-check all items
|
||||||
|
if addon.Modules.ItemDetection and addon.Modules.ItemDetection.ClearCache then
|
||||||
|
addon.Modules.ItemDetection:ClearCache()
|
||||||
|
end
|
||||||
|
UpdateAllUsabilityTints()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Reset timer (debounce behavior)
|
||||||
|
usabilityCheckFrame.elapsed = 0
|
||||||
|
usabilityCheckFrame.pending = true
|
||||||
|
usabilityCheckFrame:Show()
|
||||||
|
end
|
||||||
|
|
||||||
-- Get player race icon path (using racial ability icons)
|
-- Get player race icon path (using racial ability icons)
|
||||||
function Guda_GetPlayerRaceIcon()
|
function Guda_GetPlayerRaceIcon()
|
||||||
local _, race = UnitRace("player")
|
local _, race = UnitRace("player")
|
||||||
@@ -121,6 +183,10 @@ function Guda_BagFrame_OnShow(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
BagFrame:Update()
|
BagFrame:Update()
|
||||||
|
|
||||||
|
-- Schedule deferred usability check to fix false positives from uncached item data
|
||||||
|
-- This runs after a short delay when item info is fully loaded by the WoW client
|
||||||
|
ScheduleDeferredUsabilityCheck()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- OnHide
|
-- OnHide
|
||||||
@@ -143,6 +209,9 @@ function Guda_BagFrame_OnHide(self)
|
|||||||
throttleFrame:Hide()
|
throttleFrame:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cancel any pending deferred usability check (debounce safety)
|
||||||
|
CancelDeferredUsabilityCheck()
|
||||||
|
|
||||||
-- Clean up all buttons when frame is hidden (safe since we're not displaying)
|
-- Clean up all buttons when frame is hidden (safe since we're not displaying)
|
||||||
-- Use itemButtons hash instead of GetChildren() to avoid table allocation
|
-- Use itemButtons hash instead of GetChildren() to avoid table allocation
|
||||||
for _, bagParent in pairs(bagParents) do
|
for _, bagParent in pairs(bagParents) do
|
||||||
@@ -1774,7 +1843,7 @@ function Guda_BagFrame_Sort()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if we're in category view - only merge stacks
|
-- Check if we're in category view - restack and clean
|
||||||
local sortBtn = getglobal("Guda_BagFrame_SortButton")
|
local sortBtn = getglobal("Guda_BagFrame_SortButton")
|
||||||
if sortBtn and sortBtn.isCategoryView then
|
if sortBtn and sortBtn.isCategoryView then
|
||||||
Guda_BagFrame_MergeStacks()
|
Guda_BagFrame_MergeStacks()
|
||||||
@@ -1793,10 +1862,11 @@ function Guda_BagFrame_Sort()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Merge stacks only (for category view) - queue-based approach like BagShui
|
-- Restack and Clean (for category view) - merges stacks and refreshes view
|
||||||
|
-- Queue-based approach like BagShui
|
||||||
function Guda_BagFrame_MergeStacks()
|
function Guda_BagFrame_MergeStacks()
|
||||||
if currentViewChar then
|
if currentViewChar then
|
||||||
addon:Print("Cannot merge stacks for another character!")
|
addon:Print("Cannot restack for another character!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1896,7 +1966,13 @@ function Guda_BagFrame_MergeStacks()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if table.getn(moveQueue) == 0 then
|
if table.getn(moveQueue) == 0 then
|
||||||
addon:Print("No stacks to merge")
|
-- No stacks to merge, just do a clean refresh
|
||||||
|
-- Clear item detection cache to force fresh tooltip scans
|
||||||
|
if addon.Modules.ItemDetection and addon.Modules.ItemDetection.ClearCache then
|
||||||
|
addon.Modules.ItemDetection:ClearCache()
|
||||||
|
end
|
||||||
|
BagFrame:Update()
|
||||||
|
addon:Print("View refreshed (no stacks to merge)")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1911,10 +1987,15 @@ function Guda_BagFrame_MergeStacks()
|
|||||||
|
|
||||||
local function ProcessNextMove()
|
local function ProcessNextMove()
|
||||||
if queueIndex > table.getn(moveQueue) then
|
if queueIndex > table.getn(moveQueue) then
|
||||||
addon:Print("Merged " .. totalMoves .. " stack(s)")
|
|
||||||
addon.Modules.SortEngine.sortingInProgress = false
|
addon.Modules.SortEngine.sortingInProgress = false
|
||||||
addon.Modules.SortEngine:UpdateSortButtonState(false)
|
addon.Modules.SortEngine:UpdateSortButtonState(false)
|
||||||
|
-- Clear item detection cache to force fresh tooltip scans
|
||||||
|
if addon.Modules.ItemDetection and addon.Modules.ItemDetection.ClearCache then
|
||||||
|
addon.Modules.ItemDetection:ClearCache()
|
||||||
|
end
|
||||||
|
-- Refresh the view
|
||||||
BagFrame:Update()
|
BagFrame:Update()
|
||||||
|
addon:Print("Restacked " .. totalMoves .. " stack(s)")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -146,8 +146,8 @@
|
|||||||
<OnEnter>
|
<OnEnter>
|
||||||
GameTooltip:SetOwner(this, "ANCHOR_TOP")
|
GameTooltip:SetOwner(this, "ANCHOR_TOP")
|
||||||
if this.isCategoryView then
|
if this.isCategoryView then
|
||||||
GameTooltip:SetText("Merge Stacks")
|
GameTooltip:SetText("Restack and Clean")
|
||||||
GameTooltip:AddLine("Combines split stacks of the same item", 0.7, 0.7, 0.7)
|
GameTooltip:AddLine("Merges split stacks and refreshes the view", 0.7, 0.7, 0.7)
|
||||||
else
|
else
|
||||||
GameTooltip:SetText("Sort Bags")
|
GameTooltip:SetText("Sort Bags")
|
||||||
end
|
end
|
||||||
|
|||||||
+92
-7
@@ -21,6 +21,68 @@ local recentlyEmptiedSlots = {}
|
|||||||
-- Global click catcher for clearing bank search focus
|
-- Global click catcher for clearing bank search focus
|
||||||
local bankClickCatcher = nil
|
local bankClickCatcher = nil
|
||||||
|
|
||||||
|
--=====================================================
|
||||||
|
-- Deferred Usability Tint System
|
||||||
|
-- Prevents false positives when item data isn't fully loaded on bank open
|
||||||
|
-- Uses debouncing to handle rapid open/close safely
|
||||||
|
--=====================================================
|
||||||
|
local bankUsabilityCheckFrame = nil
|
||||||
|
local BANK_USABILITY_CHECK_DELAY = 0.25 -- Delay before re-checking usability (seconds)
|
||||||
|
|
||||||
|
-- Cancel any pending deferred usability check
|
||||||
|
local function CancelBankDeferredUsabilityCheck()
|
||||||
|
if bankUsabilityCheckFrame then
|
||||||
|
bankUsabilityCheckFrame:Hide()
|
||||||
|
bankUsabilityCheckFrame.pending = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update usability tints on all visible bank item buttons
|
||||||
|
local function UpdateAllBankUsabilityTints()
|
||||||
|
if not Guda_BankFrame or not Guda_BankFrame:IsShown() then return end
|
||||||
|
|
||||||
|
for _, bagParent in pairs(bankBagParents) do
|
||||||
|
if bagParent and bagParent.itemButtons then
|
||||||
|
for button in pairs(bagParent.itemButtons) do
|
||||||
|
if button.hasItem and button:IsShown() and Guda_ItemButton_UpdateUsableTint then
|
||||||
|
Guda_ItemButton_UpdateUsableTint(button)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Schedule a deferred usability check with debouncing
|
||||||
|
local function ScheduleBankDeferredUsabilityCheck()
|
||||||
|
-- Create frame on first use
|
||||||
|
if not bankUsabilityCheckFrame then
|
||||||
|
bankUsabilityCheckFrame = CreateFrame("Frame")
|
||||||
|
bankUsabilityCheckFrame:Hide()
|
||||||
|
bankUsabilityCheckFrame.elapsed = 0
|
||||||
|
bankUsabilityCheckFrame.pending = false
|
||||||
|
bankUsabilityCheckFrame:SetScript("OnUpdate", function()
|
||||||
|
this.elapsed = this.elapsed + arg1
|
||||||
|
if this.elapsed >= BANK_USABILITY_CHECK_DELAY then
|
||||||
|
this:Hide()
|
||||||
|
this.pending = false
|
||||||
|
-- Only run if bank is still open
|
||||||
|
if Guda_BankFrame and Guda_BankFrame:IsShown() then
|
||||||
|
-- Clear detection cache and re-check all items
|
||||||
|
if addon.Modules.ItemDetection and addon.Modules.ItemDetection.ClearCache then
|
||||||
|
addon.Modules.ItemDetection:ClearCache()
|
||||||
|
end
|
||||||
|
UpdateAllBankUsabilityTints()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Reset timer (debounce behavior)
|
||||||
|
bankUsabilityCheckFrame.elapsed = 0
|
||||||
|
bankUsabilityCheckFrame.pending = true
|
||||||
|
bankUsabilityCheckFrame:Show()
|
||||||
|
end
|
||||||
|
|
||||||
-- Clear recently emptied slots (called when view is reset or frame hidden)
|
-- Clear recently emptied slots (called when view is reset or frame hidden)
|
||||||
function BankFrame:ClearRecentlyEmptiedSlots()
|
function BankFrame:ClearRecentlyEmptiedSlots()
|
||||||
for k in pairs(recentlyEmptiedSlots) do
|
for k in pairs(recentlyEmptiedSlots) do
|
||||||
@@ -125,7 +187,11 @@ function Guda_BankFrame_OnShow(self)
|
|||||||
end
|
end
|
||||||
|
|
||||||
BankFrame:Update()
|
BankFrame:Update()
|
||||||
end
|
|
||||||
|
-- Schedule deferred usability check to fix false positives from uncached item data
|
||||||
|
-- This runs after a short delay when item info is fully loaded by the WoW client
|
||||||
|
ScheduleBankDeferredUsabilityCheck()
|
||||||
|
end
|
||||||
|
|
||||||
-- OnHide
|
-- OnHide
|
||||||
function Guda_BankFrame_OnHide(self)
|
function Guda_BankFrame_OnHide(self)
|
||||||
@@ -141,6 +207,9 @@ function Guda_BankFrame_OnHide(self)
|
|||||||
throttleFrame:Hide()
|
throttleFrame:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Cancel any pending deferred usability check (debounce safety)
|
||||||
|
CancelBankDeferredUsabilityCheck()
|
||||||
|
|
||||||
-- Clear recently emptied slots tracking (reset placeholders)
|
-- Clear recently emptied slots tracking (reset placeholders)
|
||||||
BankFrame:ClearRecentlyEmptiedSlots()
|
BankFrame:ClearRecentlyEmptiedSlots()
|
||||||
|
|
||||||
@@ -1412,7 +1481,7 @@ function Guda_BankFrame_Sort()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if we're in category view - only merge stacks
|
-- Check if we're in category view - restack and clean
|
||||||
local sortBtn = getglobal("Guda_BankFrame_SortButton")
|
local sortBtn = getglobal("Guda_BankFrame_SortButton")
|
||||||
if sortBtn and sortBtn.isCategoryView then
|
if sortBtn and sortBtn.isCategoryView then
|
||||||
Guda_BankFrame_MergeStacks()
|
Guda_BankFrame_MergeStacks()
|
||||||
@@ -1431,15 +1500,16 @@ function Guda_BankFrame_Sort()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Merge stacks only (for category view) - queue-based approach like BagShui
|
-- Restack and Clean (for category view) - merges stacks and refreshes view
|
||||||
|
-- Queue-based approach like BagShui
|
||||||
function Guda_BankFrame_MergeStacks()
|
function Guda_BankFrame_MergeStacks()
|
||||||
if isReadOnlyMode or currentViewChar then
|
if isReadOnlyMode or currentViewChar then
|
||||||
addon:Print("Cannot merge stacks in read-only mode!")
|
addon:Print("Cannot restack in read-only mode!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not addon.Modules.BankScanner:IsBankOpen() then
|
if not addon.Modules.BankScanner:IsBankOpen() then
|
||||||
addon:Print("Bank must be open to merge stacks!")
|
addon:Print("Bank must be open to restack!")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1539,7 +1609,15 @@ function Guda_BankFrame_MergeStacks()
|
|||||||
end
|
end
|
||||||
|
|
||||||
if table.getn(moveQueue) == 0 then
|
if table.getn(moveQueue) == 0 then
|
||||||
addon:Print("No stacks to merge")
|
-- No stacks to merge, just do a clean refresh
|
||||||
|
BankFrame:ClearRecentlyEmptiedSlots()
|
||||||
|
addon.Modules.BankScanner:InvalidateCache()
|
||||||
|
-- Clear item detection cache to force fresh tooltip scans
|
||||||
|
if addon.Modules.ItemDetection and addon.Modules.ItemDetection.ClearCache then
|
||||||
|
addon.Modules.ItemDetection:ClearCache()
|
||||||
|
end
|
||||||
|
BankFrame:Update()
|
||||||
|
addon:Print("View refreshed (no stacks to merge)")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1554,10 +1632,17 @@ function Guda_BankFrame_MergeStacks()
|
|||||||
|
|
||||||
local function ProcessNextMove()
|
local function ProcessNextMove()
|
||||||
if queueIndex > table.getn(moveQueue) then
|
if queueIndex > table.getn(moveQueue) then
|
||||||
addon:Print("Merged " .. totalMoves .. " stack(s)")
|
|
||||||
addon.Modules.SortEngine.sortingInProgress = false
|
addon.Modules.SortEngine.sortingInProgress = false
|
||||||
addon.Modules.SortEngine:UpdateSortButtonState(false)
|
addon.Modules.SortEngine:UpdateSortButtonState(false)
|
||||||
|
-- Clear all caches for a clean view after restacking
|
||||||
|
BankFrame:ClearRecentlyEmptiedSlots()
|
||||||
|
addon.Modules.BankScanner:InvalidateCache()
|
||||||
|
-- Clear item detection cache to force fresh tooltip scans
|
||||||
|
if addon.Modules.ItemDetection and addon.Modules.ItemDetection.ClearCache then
|
||||||
|
addon.Modules.ItemDetection:ClearCache()
|
||||||
|
end
|
||||||
BankFrame:Update()
|
BankFrame:Update()
|
||||||
|
addon:Print("Restacked " .. totalMoves .. " stack(s)")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -99,8 +99,8 @@
|
|||||||
<OnEnter>
|
<OnEnter>
|
||||||
GameTooltip:SetOwner(this, "ANCHOR_TOP")
|
GameTooltip:SetOwner(this, "ANCHOR_TOP")
|
||||||
if this.isCategoryView then
|
if this.isCategoryView then
|
||||||
GameTooltip:SetText("Merge Stacks")
|
GameTooltip:SetText("Restack and Clean")
|
||||||
GameTooltip:AddLine("Combines split stacks of the same item", 0.7, 0.7, 0.7)
|
GameTooltip:AddLine("Merges split stacks and refreshes the view", 0.7, 0.7, 0.7)
|
||||||
else
|
else
|
||||||
GameTooltip:SetText("Sort Bank")
|
GameTooltip:SetText("Sort Bank")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user