from bank (cat) to bag case
This commit is contained in:
+23
-3
@@ -45,7 +45,18 @@ end
|
||||
|
||||
-- Get cached bank data, or scan if cache is invalid
|
||||
function BankScanner:GetBankData()
|
||||
if not bankOpen then
|
||||
-- Check if bank is accessible (either officially open OR we can access bank slots)
|
||||
local bankAccessible = bankOpen
|
||||
if not bankAccessible then
|
||||
-- Try to access main bank - if it has slots, bank is actually accessible
|
||||
local testSlots = GetContainerNumSlots(-1)
|
||||
if testSlots and testSlots > 0 then
|
||||
bankAccessible = true
|
||||
addon:DebugCategory("GetBankData: bankOpen=false but bank accessible (%d slots)", testSlots)
|
||||
end
|
||||
end
|
||||
|
||||
if not bankAccessible then
|
||||
return {}
|
||||
end
|
||||
|
||||
@@ -118,8 +129,17 @@ end
|
||||
|
||||
-- Scan all bank bags and return data (full scan)
|
||||
function BankScanner:ScanBank()
|
||||
if not bankOpen then
|
||||
addon:Debug("Cannot scan bank - not open")
|
||||
-- Check if bank is accessible (officially open OR slots are readable)
|
||||
local bankAccessible = bankOpen
|
||||
if not bankAccessible then
|
||||
local testSlots = GetContainerNumSlots(-1)
|
||||
if testSlots and testSlots > 0 then
|
||||
bankAccessible = true
|
||||
end
|
||||
end
|
||||
|
||||
if not bankAccessible then
|
||||
addon:Debug("Cannot scan bank - not accessible")
|
||||
return {}
|
||||
end
|
||||
|
||||
|
||||
+189
-26
@@ -15,9 +15,54 @@ local isReadOnlyMode = false -- Track if viewing saved bank (read-only) or live
|
||||
local hiddenBankBags = {} -- Track which bank bags are hidden (bagID -> true/false)
|
||||
local bankBagParents = {} -- Parent frames per bank bag (same approach as BagFrame)
|
||||
local bankSlotToButton = {} -- Fast O(1) lookup: bankSlotToButton[bagID][slotID] = button
|
||||
-- Track empty slots that should show as placeholders in Category View
|
||||
-- Format: recentlyEmptiedSlots[bagID][slotID] = { category = "CategoryName", timestamp = time }
|
||||
local recentlyEmptiedSlots = {}
|
||||
-- Global click catcher for clearing bank search focus
|
||||
local bankClickCatcher = nil
|
||||
|
||||
-- Clear recently emptied slots (called when view is reset or frame hidden)
|
||||
function BankFrame:ClearRecentlyEmptiedSlots()
|
||||
for k in pairs(recentlyEmptiedSlots) do
|
||||
recentlyEmptiedSlots[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Mark a slot as recently emptied (preserves its category and sort info for placeholder display)
|
||||
function BankFrame:MarkSlotAsEmptied(bagID, slotID, category, itemData)
|
||||
if not recentlyEmptiedSlots[bagID] then
|
||||
recentlyEmptiedSlots[bagID] = {}
|
||||
end
|
||||
-- Store sort-relevant properties from the original item to maintain position
|
||||
recentlyEmptiedSlots[bagID][slotID] = {
|
||||
category = category or "Miscellaneous",
|
||||
timestamp = GetTime(),
|
||||
-- Preserve sort properties from original item
|
||||
quality = itemData and itemData.quality or 0,
|
||||
name = itemData and itemData.name or "",
|
||||
iLevel = itemData and itemData.iLevel or 0,
|
||||
}
|
||||
addon:DebugCategory("Marked slot %d:%d as emptied (category: %s)", bagID, slotID, category or "Miscellaneous")
|
||||
end
|
||||
|
||||
-- Check if a slot is marked as recently emptied
|
||||
function BankFrame:IsSlotRecentlyEmptied(bagID, slotID)
|
||||
return recentlyEmptiedSlots[bagID] and recentlyEmptiedSlots[bagID][slotID]
|
||||
end
|
||||
|
||||
-- Get the category of a recently emptied slot
|
||||
function BankFrame:GetEmptiedSlotCategory(bagID, slotID)
|
||||
local info = recentlyEmptiedSlots[bagID] and recentlyEmptiedSlots[bagID][slotID]
|
||||
return info and info.category or nil
|
||||
end
|
||||
|
||||
-- Remove a slot from recently emptied (when item is placed back)
|
||||
function BankFrame:UnmarkSlotAsEmptied(bagID, slotID)
|
||||
if recentlyEmptiedSlots[bagID] then
|
||||
recentlyEmptiedSlots[bagID][slotID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- OnLoad
|
||||
function Guda_BankFrame_OnLoad(self)
|
||||
-- Set up initial backdrop
|
||||
@@ -96,6 +141,9 @@ function Guda_BankFrame_OnHide(self)
|
||||
throttleFrame:Hide()
|
||||
end
|
||||
|
||||
-- Clear recently emptied slots tracking (reset placeholders)
|
||||
BankFrame:ClearRecentlyEmptiedSlots()
|
||||
|
||||
-- Close the actual Blizzard bank too
|
||||
local blizzardBankFrame = getglobal("BankFrame")
|
||||
if blizzardBankFrame and blizzardBankFrame:IsShown() then
|
||||
@@ -190,6 +238,23 @@ function BankFrame:UpdateSingleSlot(bagID, slotID, passedButton)
|
||||
|
||||
addon:DebugCategory("UpdateSingleSlot: bag=%d slot=%d hasItem=%s -> updating button", bagID, slotID, itemLink and "yes" or "no")
|
||||
|
||||
-- Track when slot becomes empty in Category View (for placeholder display)
|
||||
local viewType = addon.Modules.DB:GetSetting("bankViewType") or "single"
|
||||
if viewType == "category" then
|
||||
local hadItem = targetButton.itemData and targetButton.itemData.link
|
||||
local hasItem = itemData and itemData.link
|
||||
|
||||
if hadItem and not hasItem then
|
||||
-- Item was removed - mark slot as emptied with its category and sort info
|
||||
local category = targetButton.itemCategory or "Miscellaneous"
|
||||
local oldItemData = targetButton.itemData -- Get the old item data before it's cleared
|
||||
self:MarkSlotAsEmptied(bagID, slotID, category, oldItemData)
|
||||
elseif hasItem and not hadItem then
|
||||
-- Item was added - remove from emptied tracking
|
||||
self:UnmarkSlotAsEmptied(bagID, slotID)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the button
|
||||
local matchesFilter = self:PassesSearchFilter(itemData)
|
||||
Guda_ItemButton_SetItem(targetButton, bagID, slotID, itemData, true, nil, matchesFilter, isReadOnlyMode)
|
||||
@@ -416,15 +481,25 @@ function BankFrame:Update()
|
||||
getglobal("Guda_BankFrame_Title"):SetText(currentViewChar .. "'s Bank")
|
||||
else
|
||||
-- Viewing current character's bank
|
||||
if bankIsOpen then
|
||||
-- Bank is actually open - use cached data for performance
|
||||
-- Use live data if bank is officially open OR if we can access bank data
|
||||
-- (handles edge cases where IsBankOpen returns false but bank is still accessible)
|
||||
local useLiveData = bankIsOpen
|
||||
if not useLiveData then
|
||||
-- Try to get live data anyway - if bank bags are accessible, use live data
|
||||
local testSlots = GetContainerNumSlots(-1) -- Main bank
|
||||
if testSlots and testSlots > 0 then
|
||||
useLiveData = true
|
||||
addon:DebugCategory("Update: IsBankOpen=false but bank accessible, using live data")
|
||||
end
|
||||
end
|
||||
|
||||
local playerName = addon.Modules.DB:GetPlayerFullName()
|
||||
if useLiveData then
|
||||
-- Bank is accessible - use live data
|
||||
bankData = addon.Modules.BankScanner:GetBankData()
|
||||
-- Use current character's name for the title
|
||||
local playerName = addon.Modules.DB:GetPlayerFullName()
|
||||
getglobal("Guda_BankFrame_Title"):SetText(playerName .. "'s Bank")
|
||||
else
|
||||
-- Bank is closed - use saved data (read-only mode)
|
||||
local playerName = addon.Modules.DB:GetPlayerFullName()
|
||||
-- Bank is truly closed - use saved data (read-only mode)
|
||||
bankData = addon.Modules.DB:GetCharacterBank(playerName)
|
||||
getglobal("Guda_BankFrame_Title"):SetText(playerName .. "'s Bank")
|
||||
end
|
||||
@@ -443,6 +518,20 @@ function BankFrame:Update()
|
||||
end
|
||||
|
||||
if viewType == "category" then
|
||||
-- Debug: check bankData before display
|
||||
local bagCount = 0
|
||||
local totalItems = 0
|
||||
for bagID, bag in pairs(bankData or {}) do
|
||||
bagCount = bagCount + 1
|
||||
if bag and bag.slots then
|
||||
for slotID, item in pairs(bag.slots) do
|
||||
if item then
|
||||
totalItems = totalItems + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
addon:DebugCategory("Update: bankData has %d bags, %d total items", bagCount, totalItems)
|
||||
self:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
||||
-- Show sort button with merge icon/tooltip for category view
|
||||
local sortBtn = getglobal("Guda_BankFrame_SortButton")
|
||||
@@ -504,13 +593,59 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
||||
local categoryList = Guda_CategoryList
|
||||
|
||||
-- Categorize all items using centralized function
|
||||
local totalItemsCategorized = 0
|
||||
for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
|
||||
if not hiddenBankBags[bagID] then
|
||||
local bag = bankData[bagID]
|
||||
if bag and bag.slots then
|
||||
local bagItemCount = 0
|
||||
for slotID, itemData in pairs(bag.slots) do
|
||||
if itemData then
|
||||
Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems, isOtherChar)
|
||||
bagItemCount = bagItemCount + 1
|
||||
totalItemsCategorized = totalItemsCategorized + 1
|
||||
end
|
||||
end
|
||||
if bagItemCount > 0 then
|
||||
addon:DebugCategory("DisplayItemsByCategory: bag %d has %d items", bagID, bagItemCount)
|
||||
end
|
||||
else
|
||||
addon:DebugCategory("DisplayItemsByCategory: bag %d has no data (bag=%s, slots=%s)",
|
||||
bagID, tostring(bag ~= nil), tostring(bag and bag.slots ~= nil))
|
||||
end
|
||||
end
|
||||
end
|
||||
addon:DebugCategory("DisplayItemsByCategory: total items categorized = %d", totalItemsCategorized)
|
||||
|
||||
-- Add recently emptied slots as empty placeholders in their respective categories
|
||||
-- This preserves the visual position of items that were just moved out
|
||||
if not isOtherChar then
|
||||
for bagID, slots in pairs(recentlyEmptiedSlots) do
|
||||
if not hiddenBankBags[bagID] then
|
||||
for slotID, info in pairs(slots) do
|
||||
-- Only add if slot is actually empty (not refilled)
|
||||
local currentLink = GetContainerItemLink(bagID, slotID)
|
||||
if not currentLink then
|
||||
local catName = info.category
|
||||
if catName and categories[catName] then
|
||||
-- Add empty placeholder to category with original item's sort properties
|
||||
-- This keeps the placeholder in the same visual position as the original item
|
||||
table.insert(categories[catName], {
|
||||
bagID = bagID,
|
||||
slotID = slotID,
|
||||
itemData = {
|
||||
-- Fake itemData with sort-relevant properties from original item
|
||||
quality = info.quality or 0,
|
||||
name = info.name or "",
|
||||
iLevel = info.iLevel or 0,
|
||||
},
|
||||
isEmpty = true, -- Mark as placeholder (display will show empty slot)
|
||||
})
|
||||
addon:DebugCategory("Added empty placeholder for %d:%d to category %s", bagID, slotID, catName)
|
||||
end
|
||||
else
|
||||
-- Slot has item now, remove from tracking
|
||||
slots[slotID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -591,7 +726,8 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
||||
for _, item in ipairs(items) do
|
||||
local bagID = item.bagID
|
||||
local slot = item.slotID
|
||||
local itemData = item.itemData
|
||||
-- For empty placeholders, pass nil itemData so button shows as empty slot
|
||||
local itemData = item.isEmpty and nil or item.itemData
|
||||
|
||||
local bagParent = self:GetBagParent(bagID)
|
||||
local button = Guda_GetItemButton(bagParent)
|
||||
@@ -606,9 +742,15 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
||||
local matchesFilter = self:PassesSearchFilter(itemData)
|
||||
Guda_ItemButton_SetItem(button, bagID, slot, itemData, true, isOtherChar and charName or nil, matchesFilter, isOtherChar or isReadOnlyMode)
|
||||
button.inUse = true
|
||||
button.itemCategory = catName -- Track category for empty slot placeholders
|
||||
button.isEmptyPlaceholder = item.isEmpty -- Track if this is a placeholder
|
||||
-- Populate slot lookup for O(1) access
|
||||
if not bankSlotToButton[bagID] then bankSlotToButton[bagID] = {} end
|
||||
bankSlotToButton[bagID][slot] = button
|
||||
-- Remove from recently emptied only if slot now has an item (not a placeholder)
|
||||
if itemData then
|
||||
self:UnmarkSlotAsEmptied(bagID, slot)
|
||||
end
|
||||
|
||||
col = col + 1
|
||||
if col >= blockCols then
|
||||
@@ -652,6 +794,10 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
||||
break
|
||||
end
|
||||
end
|
||||
-- Also show bottom section if there are free slots (for Empty drop target)
|
||||
if totalFreeSlots > 0 then
|
||||
hasAnyBottom = true
|
||||
end
|
||||
|
||||
if hasAnyBottom then
|
||||
y = y - 10
|
||||
@@ -1764,8 +1910,16 @@ function BankFrame:Initialize()
|
||||
bankThrottle.frame:Hide()
|
||||
bankThrottle.pending = false
|
||||
bankThrottle.elapsed = 0
|
||||
if addon.Modules.BankScanner:IsBankOpen() and not currentViewChar then
|
||||
-- Update if bank is open OR our frame is shown (for edge cases)
|
||||
local bankOpen = addon.Modules.BankScanner:IsBankOpen()
|
||||
local frameShown = Guda_BankFrame and Guda_BankFrame:IsShown()
|
||||
addon:DebugCategory("Throttle fired: bankOpen=%s, frameShown=%s, viewingCurrent=%s",
|
||||
tostring(bankOpen), tostring(frameShown), tostring(not currentViewChar))
|
||||
if (bankOpen or frameShown) and not currentViewChar then
|
||||
addon:DebugCategory("Throttle: calling BankFrame:Update()")
|
||||
addon.Modules.BankFrame:Update()
|
||||
else
|
||||
addon:DebugCategory("Throttle: skipped Update (conditions not met)")
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -1774,7 +1928,13 @@ function BankFrame:Initialize()
|
||||
end
|
||||
|
||||
local function ScheduleBankFrameUpdate(delay)
|
||||
if not addon.Modules.BankScanner:IsBankOpen() then return end
|
||||
-- Allow update if bank is open OR our frame is shown
|
||||
local bankOpen = addon.Modules.BankScanner:IsBankOpen()
|
||||
local frameShown = Guda_BankFrame and Guda_BankFrame:IsShown()
|
||||
if not bankOpen and not frameShown then
|
||||
addon:DebugCategory("ScheduleBankFrameUpdate: skipped (bank not open, frame not shown)")
|
||||
return
|
||||
end
|
||||
if currentViewChar then return end
|
||||
|
||||
delay = delay or bankThrottle.minDelay
|
||||
@@ -1792,10 +1952,12 @@ function BankFrame:Initialize()
|
||||
bankThrottle.delay = delay
|
||||
bankThrottle.elapsed = 0 -- Reset timer (true debounce)
|
||||
|
||||
local wasAlreadyPending = bankThrottle.pending
|
||||
if not bankThrottle.pending then
|
||||
bankThrottle.pending = true
|
||||
GetBankThrottleFrame():Show()
|
||||
end
|
||||
addon:DebugCategory("ScheduleBankFrameUpdate: delay=%s, wasAlreadyPending=%s", tostring(delay), tostring(wasAlreadyPending))
|
||||
end
|
||||
|
||||
-- NOTE: BAG_UPDATE for bank bags (5-10) is handled by the updateFrame below
|
||||
@@ -1804,7 +1966,10 @@ function BankFrame:Initialize()
|
||||
|
||||
-- Update when items get locked/unlocked (debounced for trading, mailing, etc.)
|
||||
addon.Modules.Events:Register("ITEM_LOCK_CHANGED", function()
|
||||
if not addon.Modules.BankScanner:IsBankOpen() then return end
|
||||
-- Allow if bank is open OR our frame is shown
|
||||
local bankOpen = addon.Modules.BankScanner:IsBankOpen()
|
||||
local frameShown = Guda_BankFrame and Guda_BankFrame:IsShown()
|
||||
if not bankOpen and not frameShown then return end
|
||||
if currentViewChar then return end
|
||||
-- In Category View, just update lock states visually without full redraw
|
||||
local viewType = addon.Modules.DB:GetSetting("bankViewType") or "single"
|
||||
@@ -1823,9 +1988,15 @@ function BankFrame:Initialize()
|
||||
updateFrame:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED")
|
||||
updateFrame:RegisterEvent("BAG_UPDATE")
|
||||
updateFrame:SetScript("OnEvent", function()
|
||||
-- Check if we should process bank events:
|
||||
-- 1. Bank is officially open (IsBankOpen), OR
|
||||
-- 2. Our BankFrame is shown and we're viewing current character (for edge cases)
|
||||
local bankOpen = addon.Modules.BankScanner:IsBankOpen()
|
||||
if not bankOpen then
|
||||
addon:DebugCategory("BankFrame event %s: bank not open, ignoring", event or "nil")
|
||||
local frameShown = Guda_BankFrame and Guda_BankFrame:IsShown()
|
||||
local viewingCurrent = not currentViewChar
|
||||
|
||||
if not bankOpen and not (frameShown and viewingCurrent) then
|
||||
addon:DebugCategory("BankFrame event %s: bank not open and frame not shown, ignoring", event or "nil")
|
||||
return
|
||||
end
|
||||
if currentViewChar then return end
|
||||
@@ -1845,13 +2016,9 @@ function BankFrame:Initialize()
|
||||
local success = BankFrame:UpdateSingleSlot(-1, arg1)
|
||||
addon:DebugCategory(" UpdateSingleSlot(-1, %d) = %s", arg1, tostring(success))
|
||||
if success then
|
||||
-- Cancel any pending full redraw - incremental update succeeded
|
||||
if bankThrottle.pending and bankThrottle.frame then
|
||||
addon:DebugCategory(" Canceling pending full redraw")
|
||||
bankThrottle.pending = false
|
||||
bankThrottle.frame:Hide()
|
||||
end
|
||||
return -- Success, no full redraw needed
|
||||
-- Incremental update succeeded - no need for full redraw for THIS slot
|
||||
-- But don't cancel pending redraws - other slots might need them
|
||||
return
|
||||
end
|
||||
end
|
||||
-- Fallback: full redraw (sorting or single-slot failed)
|
||||
@@ -1871,13 +2038,9 @@ function BankFrame:Initialize()
|
||||
local result = BankFrame:UpdateChangedSlots(arg1)
|
||||
addon:DebugCategory(" UpdateChangedSlots(%d) = %d", arg1, result)
|
||||
if result >= 0 then
|
||||
-- Cancel any pending full redraw - incremental update succeeded
|
||||
if bankThrottle.pending and bankThrottle.frame then
|
||||
addon:DebugCategory(" Canceling pending full redraw")
|
||||
bankThrottle.pending = false
|
||||
bankThrottle.frame:Hide()
|
||||
end
|
||||
return -- Success, no full redraw needed
|
||||
-- Incremental update succeeded - no need for full redraw for THIS bag
|
||||
-- But don't cancel pending redraws - other changes might need them
|
||||
return
|
||||
end
|
||||
-- Fall through to full redraw
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user