refactory: centralized category view
This commit is contained in:
+12
-148
@@ -387,109 +387,18 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
local perRow = addon.Modules.DB:GetSetting("bagColumns") or 10
|
local perRow = addon.Modules.DB:GetSetting("bagColumns") or 10
|
||||||
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
|
||||||
|
|
||||||
-- Group items by category
|
-- Use centralized category initialization
|
||||||
local categories = {}
|
local categories, specialItems = Guda_InitCategories()
|
||||||
local categoryList = {
|
local categoryList = Guda_CategoryList
|
||||||
"Weapon", "Armor", "BoE", "Consumable", "Food", "Drink", "Trade Goods", "Reagent", "Recipe", "Quiver", "Container", "Soul Bag", "Miscellaneous", "Quest", "Junk", "Class Items", "Keyring"
|
|
||||||
}
|
|
||||||
for _, cat in ipairs(categoryList) do categories[cat] = {} end
|
|
||||||
|
|
||||||
local specialItems = {
|
|
||||||
Hearthstone = {},
|
|
||||||
Mount = {},
|
|
||||||
Tools = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
-- Categorize all items using centralized function
|
||||||
for _, bagID in ipairs(addon.Constants.BAGS) do
|
for _, bagID in ipairs(addon.Constants.BAGS) do
|
||||||
if not hiddenBags[bagID] then
|
if not hiddenBags[bagID] then
|
||||||
local bag = bagData[bagID]
|
local bag = bagData[bagID]
|
||||||
if bag and bag.slots then
|
if bag and bag.slots then
|
||||||
for slotID, itemData in pairs(bag.slots) do
|
for slotID, itemData in pairs(bag.slots) do
|
||||||
if itemData then
|
if itemData then
|
||||||
local cat = "Miscellaneous"
|
Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems, isOtherChar)
|
||||||
local itemName = itemData.name or ""
|
|
||||||
local itemType = itemData.type or ""
|
|
||||||
|
|
||||||
-- Detect consumable restore/eat/drink tag for current character only
|
|
||||||
if not isOtherChar and addon.Modules.Utils and addon.Modules.Utils.GetConsumableRestoreTag then
|
|
||||||
local tag = addon.Modules.Utils:GetConsumableRestoreTag(bagID, slotID)
|
|
||||||
if tag then
|
|
||||||
itemData.restoreTag = tag
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Priority 1: Special items (Hearthstone, Mounts, Tools)
|
|
||||||
if string.find(itemName, "Hearthstone") then
|
|
||||||
table.insert(specialItems.Hearthstone, {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
elseif addon.Modules.SortEngine and addon.Modules.SortEngine.IsMount and addon.Modules.SortEngine.IsMount(itemData.texture) then
|
|
||||||
table.insert(specialItems.Mount, {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
elseif string.find(itemName, "Runed .* Rod") or
|
|
||||||
itemType == "Fishing Pole" or
|
|
||||||
string.find(itemName, "Mining Pick") or
|
|
||||||
string.find(itemName, "Blacksmith Hammer") or
|
|
||||||
itemName == "Arclight Spanner" or
|
|
||||||
itemName == "Gyromatic Micro-Adjustor" or
|
|
||||||
itemName == "Philosopher's Stone" or
|
|
||||||
string.find(itemName, "Skinning Knife") or
|
|
||||||
itemName == "Blood Scythe" then
|
|
||||||
table.insert(specialItems.Tools, {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
|
|
||||||
-- Priority 2: Class Items (Soul Shards, Arrows, Bullets)
|
|
||||||
elseif addon.Modules.Utils:IsSoulShard(itemData.link) or
|
|
||||||
itemData.class == "Projectile" or
|
|
||||||
itemData.subclass == "Arrow" or
|
|
||||||
itemData.subclass == "Bullet" then
|
|
||||||
table.insert(categories["Class Items"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
|
|
||||||
-- Priority 3: Quest Items
|
|
||||||
elseif (not isOtherChar and addon.Modules.Utils:IsQuestItemTooltip(bagID, slotID)) or itemData.class == "Quest" then
|
|
||||||
table.insert(categories["Quest"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
|
|
||||||
-- Priority 4: Junk (Gray items)
|
|
||||||
elseif itemData.quality == 0 or addon.Modules.Utils:IsItemGrayTooltip(bagID, slotID, itemData.link) then
|
|
||||||
table.insert(categories["Junk"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
|
|
||||||
-- Priority 5: Food and Drink
|
|
||||||
elseif itemData.class == "Consumable" then
|
|
||||||
cat = "Consumable"
|
|
||||||
local sub = itemData.subclass or ""
|
|
||||||
if sub == "Food & Drink" or string.find(sub, "Food") or string.find(sub, "Drink") then
|
|
||||||
if string.find(sub, "Drink") then
|
|
||||||
cat = "Drink"
|
|
||||||
else
|
|
||||||
cat = "Food"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
|
|
||||||
-- Priority 6: BoE Equipment (Armor/Weapons that bind when equipped)
|
|
||||||
elseif (itemData.class == "Weapon" or itemData.class == "Armor") and
|
|
||||||
not isOtherChar then
|
|
||||||
-- Check for BoE
|
|
||||||
local isBoE = addon.Modules.Utils:IsBindOnEquip(bagID, slotID)
|
|
||||||
if isBoE then
|
|
||||||
table.insert(categories["BoE"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
else
|
|
||||||
-- Not BoE, put in regular category
|
|
||||||
table.insert(categories[itemData.class], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Priority 7: Equipment (other equippable items like trinkets, rings, or viewing other character's gear)
|
|
||||||
elseif itemData.equipSlot and itemData.equipSlot ~= "" then
|
|
||||||
-- For other characters, can't scan tooltip so just categorize normally
|
|
||||||
if itemData.class == "Weapon" or itemData.class == "Armor" then
|
|
||||||
cat = itemData.class
|
|
||||||
else
|
|
||||||
cat = "Armor"
|
|
||||||
end
|
|
||||||
table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
|
|
||||||
-- Priority 8: Other Categories
|
|
||||||
else
|
|
||||||
cat = itemData.class or "Miscellaneous"
|
|
||||||
if not categories[cat] then cat = "Miscellaneous" end
|
|
||||||
table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -540,50 +449,14 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
local items = categories[catName]
|
local items = categories[catName]
|
||||||
local numItems = items and table.getn(items) or 0
|
local numItems = items and table.getn(items) or 0
|
||||||
if numItems > 0 then
|
if numItems > 0 then
|
||||||
-- Sort items in category: Subclass > Quality > Name
|
-- Sort items using centralized sorter
|
||||||
table.sort(items, function(a, b)
|
Guda_SortCategoryItems(items)
|
||||||
-- Rank Trade Goods: meat (name ends with 'meat') = 2, egg (contains 'egg') = 1, others = 0
|
|
||||||
local function tgRank(d)
|
|
||||||
if not d or not d.name then return 0 end
|
|
||||||
local t = d.type or d.class or ""
|
|
||||||
if t ~= "Trade Goods" then return 0 end
|
|
||||||
local n = string.lower(d.name)
|
|
||||||
if string.find(n, "meat$") then return 2 end
|
|
||||||
if string.find(n, "egg") then return 1 end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
local ra = tgRank(a.itemData)
|
|
||||||
local rb = tgRank(b.itemData)
|
|
||||||
if ra ~= rb then
|
|
||||||
return ra > rb
|
|
||||||
end
|
|
||||||
-- Priority: consumable restore tags (eat > drink > restore > nil)
|
|
||||||
local pa = a.itemData and a.itemData.restoreTag or nil
|
|
||||||
local pb = b.itemData and b.itemData.restoreTag or nil
|
|
||||||
local function pr(t)
|
|
||||||
if t == "eat" then return 3 end
|
|
||||||
if t == "drink" then return 2 end
|
|
||||||
if t == "restore" then return 1 end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
if pr(pa) ~= pr(pb) then
|
|
||||||
return pr(pa) > pr(pb)
|
|
||||||
end
|
|
||||||
-- Fallback: subclass, quality, name
|
|
||||||
if a.itemData.subclass ~= b.itemData.subclass then
|
|
||||||
return (a.itemData.subclass or "") < (b.itemData.subclass or "")
|
|
||||||
end
|
|
||||||
if a.itemData.quality ~= b.itemData.quality then
|
|
||||||
return a.itemData.quality > b.itemData.quality
|
|
||||||
end
|
|
||||||
return (a.itemData.name or "") < (b.itemData.name or "")
|
|
||||||
end)
|
|
||||||
|
|
||||||
local blockCols = numItems
|
local blockCols = numItems
|
||||||
if blockCols > perRow then blockCols = perRow end
|
if blockCols > perRow then blockCols = perRow end
|
||||||
local blockRows = math.ceil(numItems / perRow)
|
local blockRows = math.ceil(numItems / perRow)
|
||||||
local blockWidth = blockCols * (buttonSize + spacing)
|
local blockWidth = blockCols * (buttonSize + spacing)
|
||||||
local blockHeight = 20 + (blockRows * (buttonSize + spacing)) + 5 -- 20 header, 5 padding
|
local blockHeight = 20 + (blockRows * (buttonSize + spacing)) + 5
|
||||||
|
|
||||||
-- Check if it fits in current row
|
-- Check if it fits in current row
|
||||||
if currentX > 0 and currentX + blockWidth + 20 > totalWidth + 5 then
|
if currentX > 0 and currentX + blockWidth + 20 > totalWidth + 5 then
|
||||||
@@ -639,7 +512,7 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if blockHeight > rowMaxHeight then rowMaxHeight = blockHeight end
|
if blockHeight > rowMaxHeight then rowMaxHeight = blockHeight end
|
||||||
currentX = currentX + blockWidth + 20 -- 20px gap between categories
|
currentX = currentX + blockWidth + 20
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -655,9 +528,8 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
local x = startX
|
local x = startX
|
||||||
y = startY - y -- convert to coordinate relative to TOPLEFT
|
y = startY - y
|
||||||
|
|
||||||
-- Add spacing before special section
|
|
||||||
local hasAnyBottom = false
|
local hasAnyBottom = false
|
||||||
for _, sec in ipairs(bottomSections) do
|
for _, sec in ipairs(bottomSections) do
|
||||||
if table.getn(sec.items) > 0 then
|
if table.getn(sec.items) > 0 then
|
||||||
@@ -678,7 +550,6 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
numItems = (totalFreeSlots > 0) and 1 or 0
|
numItems = (totalFreeSlots > 0) and 1 or 0
|
||||||
end
|
end
|
||||||
if numItems > 0 then
|
if numItems > 0 then
|
||||||
-- Sort Tools (Hearthstone/Mounts don't usually need it but good for consistency)
|
|
||||||
if sec.name == "Tools" then
|
if sec.name == "Tools" then
|
||||||
table.sort(items, function(a, b)
|
table.sort(items, function(a, b)
|
||||||
if a.itemData.quality ~= b.itemData.quality then
|
if a.itemData.quality ~= b.itemData.quality then
|
||||||
@@ -694,14 +565,12 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
local blockWidth = blockCols * (buttonSize + spacing)
|
local blockWidth = blockCols * (buttonSize + spacing)
|
||||||
local blockHeight = 20 + (blockRows * (buttonSize + spacing))
|
local blockHeight = 20 + (blockRows * (buttonSize + spacing))
|
||||||
|
|
||||||
-- Check if it fits in current row (Inline block for bottom sections too)
|
|
||||||
if currentBottomX > 0 and currentBottomX + blockWidth + 20 > totalWidth + 5 then
|
if currentBottomX > 0 and currentBottomX + blockWidth + 20 > totalWidth + 5 then
|
||||||
currentBottomX = 0
|
currentBottomX = 0
|
||||||
y = y - sectionMaxHeight - 5
|
y = y - sectionMaxHeight - 5
|
||||||
sectionMaxHeight = 0
|
sectionMaxHeight = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add Header
|
|
||||||
local header = self:GetSectionHeader(headerIdx)
|
local header = self:GetSectionHeader(headerIdx)
|
||||||
headerIdx = headerIdx + 1
|
headerIdx = headerIdx + 1
|
||||||
header:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", x + currentBottomX, y)
|
header:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", x + currentBottomX, y)
|
||||||
@@ -714,7 +583,6 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
local sRow = 0
|
local sRow = 0
|
||||||
|
|
||||||
if sec.name == "Empty" then
|
if sec.name == "Empty" then
|
||||||
-- Display one empty slot button with count
|
|
||||||
local bagID = firstFreeBag or 0
|
local bagID = firstFreeBag or 0
|
||||||
local slotID = firstFreeSlot or 1
|
local slotID = firstFreeSlot or 1
|
||||||
local bagParent = self:GetBagParent(bagID)
|
local bagParent = self:GetBagParent(bagID)
|
||||||
@@ -731,9 +599,7 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
count = totalFreeSlots,
|
count = totalFreeSlots,
|
||||||
name = "Empty Slots"
|
name = "Empty Slots"
|
||||||
}
|
}
|
||||||
-- Use fake data but real IDs for drop handling
|
|
||||||
Guda_ItemButton_SetItem(button, bagID, slotID, emptyItemData, false, isOtherChar and charName or nil, true, true)
|
Guda_ItemButton_SetItem(button, bagID, slotID, emptyItemData, false, isOtherChar and charName or nil, true, true)
|
||||||
-- Ensure it's not actually read-only for drop behavior (it should still receive clicks/drops)
|
|
||||||
button.isReadOnly = false
|
button.isReadOnly = false
|
||||||
button.inUse = true
|
button.inUse = true
|
||||||
table.insert(itemButtons, button)
|
table.insert(itemButtons, button)
|
||||||
@@ -760,9 +626,8 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if blockHeight > sectionMaxHeight then sectionMaxHeight = blockHeight end
|
if blockHeight > sectionMaxHeight then sectionMaxHeight = blockHeight end
|
||||||
currentBottomX = currentBottomX + blockWidth + 20 -- Match the 20px gap used in top categories
|
currentBottomX = currentBottomX + blockWidth + 20
|
||||||
|
|
||||||
-- If we wrapped exactly at the end of a block
|
|
||||||
if currentBottomX >= totalWidth then
|
if currentBottomX >= totalWidth then
|
||||||
currentBottomX = 0
|
currentBottomX = 0
|
||||||
y = y - sectionMaxHeight - 5
|
y = y - sectionMaxHeight - 5
|
||||||
@@ -776,7 +641,6 @@ function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update container height
|
|
||||||
local finalHeight = math.abs(y) + 20
|
local finalHeight = math.abs(y) + 20
|
||||||
itemContainer:SetHeight(finalHeight)
|
itemContainer:SetHeight(finalHeight)
|
||||||
self:ResizeFrame(nil, nil, perRow, finalHeight)
|
self:ResizeFrame(nil, nil, perRow, finalHeight)
|
||||||
|
|||||||
+10
-109
@@ -234,100 +234,18 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
local perRow = addon.Modules.DB:GetSetting("bankColumns") or 10
|
local perRow = addon.Modules.DB:GetSetting("bankColumns") or 10
|
||||||
local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
|
local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
|
||||||
|
|
||||||
-- Group items by category
|
-- Use centralized category initialization
|
||||||
local categories = {}
|
local categories, specialItems = Guda_InitCategories()
|
||||||
local categoryList = {
|
local categoryList = Guda_CategoryList
|
||||||
"Weapon", "Armor", "Consumable", "Food", "Drink", "Trade Goods", "Reagent", "Recipe", "Quiver", "Container", "Soul Bag", "Miscellaneous", "Quest", "Junk", "Class Items"
|
|
||||||
}
|
|
||||||
for _, cat in ipairs(categoryList) do categories[cat] = {} end
|
|
||||||
|
|
||||||
local specialItems = {
|
-- Categorize all items using centralized function
|
||||||
Hearthstone = {},
|
|
||||||
Mount = {},
|
|
||||||
Tools = {},
|
|
||||||
Empty = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Helper to assign category
|
|
||||||
local function CategorizeItem(itemData, bagID, slotID)
|
|
||||||
local itemName = itemData.name or ""
|
|
||||||
local itemType = itemData.type or ""
|
|
||||||
local cat = "Miscellaneous"
|
|
||||||
|
|
||||||
-- Priority 1: Special items (Hearthstone, Mounts, Tools)
|
|
||||||
if string.find(itemName, "Hearthstone") then
|
|
||||||
table.insert(specialItems.Hearthstone, {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
return
|
|
||||||
elseif addon.Modules.SortEngine and addon.Modules.SortEngine.IsMount and addon.Modules.SortEngine.IsMount(itemData.texture) then
|
|
||||||
table.insert(specialItems.Mount, {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
return
|
|
||||||
elseif string.find(itemName, "Runed .* Rod") or
|
|
||||||
itemType == "Fishing Pole" or
|
|
||||||
string.find(itemName, "Mining Pick") or
|
|
||||||
string.find(itemName, "Blacksmith Hammer") or
|
|
||||||
itemName == "Arclight Spanner" or
|
|
||||||
itemName == "Gyromatic Micro-Adjustor" or
|
|
||||||
itemName == "Philosopher's Stone" or
|
|
||||||
string.find(itemName, "Skinning Knife") or
|
|
||||||
itemName == "Blood Scythe" then
|
|
||||||
table.insert(specialItems.Tools, {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Priority 2: Class Items (Soul Shards, Arrows, Bullets)
|
|
||||||
if addon.Modules.Utils:IsSoulShard(itemData.link) or
|
|
||||||
itemData.class == "Projectile" or
|
|
||||||
itemData.subclass == "Arrow" or
|
|
||||||
itemData.subclass == "Bullet" then
|
|
||||||
table.insert(categories["Class Items"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Priority 3: Quest Items
|
|
||||||
if (not isOtherChar and addon.Modules.Utils:IsQuestItemTooltip(bagID, slotID)) or itemData.class == "Quest" then
|
|
||||||
cat = "Quest"
|
|
||||||
|
|
||||||
-- Priority 4: Junk (Gray items)
|
|
||||||
elseif itemData.quality == 0 or addon.Modules.Utils:IsItemGrayTooltip(bagID, slotID, itemData.link) then
|
|
||||||
cat = "Junk"
|
|
||||||
|
|
||||||
-- Priority 5: Food and Drink
|
|
||||||
elseif itemData.class == "Consumable" then
|
|
||||||
cat = "Consumable"
|
|
||||||
local sub = itemData.subclass or ""
|
|
||||||
if sub == "Food & Drink" or string.find(sub, "Food") or string.find(sub, "Drink") then
|
|
||||||
if string.find(sub, "Drink") then
|
|
||||||
cat = "Drink"
|
|
||||||
else
|
|
||||||
cat = "Food"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Priority 4: Equipment (Weapon and Armor)
|
|
||||||
elseif itemData.equipSlot and itemData.equipSlot ~= "" then
|
|
||||||
if itemData.class == "Weapon" or itemData.class == "Armor" then
|
|
||||||
cat = itemData.class
|
|
||||||
else
|
|
||||||
cat = "Armor"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Priority 5: Other Categories
|
|
||||||
else
|
|
||||||
cat = itemData.class or "Miscellaneous"
|
|
||||||
end
|
|
||||||
|
|
||||||
if not categories[cat] then cat = "Miscellaneous" end
|
|
||||||
table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Bank slots
|
|
||||||
for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
|
for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
|
||||||
if not hiddenBankBags[bagID] then
|
if not hiddenBankBags[bagID] then
|
||||||
local bag = bankData[bagID]
|
local bag = bankData[bagID]
|
||||||
if bag and bag.slots then
|
if bag and bag.slots then
|
||||||
for slotID, itemData in pairs(bag.slots) do
|
for slotID, itemData in pairs(bag.slots) do
|
||||||
if itemData then
|
if itemData then
|
||||||
CategorizeItem(itemData, bagID, slotID)
|
Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems, isOtherChar)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -366,16 +284,8 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
local items = categories[catName]
|
local items = categories[catName]
|
||||||
local numItems = items and table.getn(items) or 0
|
local numItems = items and table.getn(items) or 0
|
||||||
if numItems > 0 then
|
if numItems > 0 then
|
||||||
-- Sort items in category: Subclass > Quality > Name
|
-- Sort items using centralized sorter
|
||||||
table.sort(items, function(a, b)
|
Guda_SortCategoryItems(items)
|
||||||
if a.itemData.subclass ~= b.itemData.subclass then
|
|
||||||
return (a.itemData.subclass or "") < (b.itemData.subclass or "")
|
|
||||||
end
|
|
||||||
if a.itemData.quality ~= b.itemData.quality then
|
|
||||||
return a.itemData.quality > b.itemData.quality
|
|
||||||
end
|
|
||||||
return (a.itemData.name or "") < (b.itemData.name or "")
|
|
||||||
end)
|
|
||||||
|
|
||||||
local blockCols = numItems
|
local blockCols = numItems
|
||||||
if blockCols > perRow then blockCols = perRow end
|
if blockCols > perRow then blockCols = perRow end
|
||||||
@@ -436,7 +346,7 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if blockHeight > rowMaxHeight then rowMaxHeight = blockHeight end
|
if blockHeight > rowMaxHeight then rowMaxHeight = blockHeight end
|
||||||
currentX = currentX + blockWidth + 20 -- 20px gap between categories
|
currentX = currentX + blockWidth + 20
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -452,9 +362,8 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
local x = startX
|
local x = startX
|
||||||
y = startY - y -- convert to coordinate relative to TOPLEFT
|
y = startY - y
|
||||||
|
|
||||||
-- Add spacing before special section
|
|
||||||
local hasAnyBottom = false
|
local hasAnyBottom = false
|
||||||
for _, sec in ipairs(bottomSections) do
|
for _, sec in ipairs(bottomSections) do
|
||||||
if table.getn(sec.items) > 0 then
|
if table.getn(sec.items) > 0 then
|
||||||
@@ -475,7 +384,6 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
numItems = (totalFreeSlots > 0) and 1 or 0
|
numItems = (totalFreeSlots > 0) and 1 or 0
|
||||||
end
|
end
|
||||||
if numItems > 0 then
|
if numItems > 0 then
|
||||||
-- Sort Tools (Hearthstone/Mounts don't usually need it but good for consistency)
|
|
||||||
if sec.name == "Tools" then
|
if sec.name == "Tools" then
|
||||||
table.sort(items, function(a, b)
|
table.sort(items, function(a, b)
|
||||||
if a.itemData.quality ~= b.itemData.quality then
|
if a.itemData.quality ~= b.itemData.quality then
|
||||||
@@ -491,14 +399,12 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
local blockWidth = blockCols * (buttonSize + spacing)
|
local blockWidth = blockCols * (buttonSize + spacing)
|
||||||
local blockHeight = 20 + (blockRows * (buttonSize + spacing))
|
local blockHeight = 20 + (blockRows * (buttonSize + spacing))
|
||||||
|
|
||||||
-- Check if it fits in current row (Inline block for bottom sections too)
|
|
||||||
if currentBottomX > 0 and currentBottomX + blockWidth + 20 > totalWidth + 5 then
|
if currentBottomX > 0 and currentBottomX + blockWidth + 20 > totalWidth + 5 then
|
||||||
currentBottomX = 0
|
currentBottomX = 0
|
||||||
y = y - sectionMaxHeight - 5
|
y = y - sectionMaxHeight - 5
|
||||||
sectionMaxHeight = 0
|
sectionMaxHeight = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add Header
|
|
||||||
local header = self:GetSectionHeader(headerIdx)
|
local header = self:GetSectionHeader(headerIdx)
|
||||||
headerIdx = headerIdx + 1
|
headerIdx = headerIdx + 1
|
||||||
header:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", x + currentBottomX, y)
|
header:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", x + currentBottomX, y)
|
||||||
@@ -511,7 +417,6 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
local sRow = 0
|
local sRow = 0
|
||||||
|
|
||||||
if sec.name == "Empty" then
|
if sec.name == "Empty" then
|
||||||
-- Display one empty slot button with count
|
|
||||||
local bagID = firstFreeBag or -1
|
local bagID = firstFreeBag or -1
|
||||||
local slotID = firstFreeSlot or 1
|
local slotID = firstFreeSlot or 1
|
||||||
local bagParent = self:GetBagParent(bagID)
|
local bagParent = self:GetBagParent(bagID)
|
||||||
@@ -528,9 +433,7 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
count = totalFreeSlots,
|
count = totalFreeSlots,
|
||||||
name = "Empty Slots"
|
name = "Empty Slots"
|
||||||
}
|
}
|
||||||
-- Use fake data but real IDs for drop handling
|
|
||||||
Guda_ItemButton_SetItem(button, bagID, slotID, emptyItemData, true, isOtherChar and charName or nil, true, true)
|
Guda_ItemButton_SetItem(button, bagID, slotID, emptyItemData, true, isOtherChar and charName or nil, true, true)
|
||||||
-- Ensure it's not actually read-only for drop behavior
|
|
||||||
button.isReadOnly = false
|
button.isReadOnly = false
|
||||||
button.inUse = true
|
button.inUse = true
|
||||||
else
|
else
|
||||||
@@ -555,9 +458,8 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if blockHeight > sectionMaxHeight then sectionMaxHeight = blockHeight end
|
if blockHeight > sectionMaxHeight then sectionMaxHeight = blockHeight end
|
||||||
currentBottomX = currentBottomX + blockWidth + 20 -- Match the 20px gap used in top categories
|
currentBottomX = currentBottomX + blockWidth + 20
|
||||||
|
|
||||||
-- If we wrapped exactly at the end of a block
|
|
||||||
if currentBottomX >= totalWidth then
|
if currentBottomX >= totalWidth then
|
||||||
currentBottomX = 0
|
currentBottomX = 0
|
||||||
y = y - sectionMaxHeight - 5
|
y = y - sectionMaxHeight - 5
|
||||||
@@ -571,7 +473,6 @@ function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Update container height
|
|
||||||
local finalHeight = math.abs(y) + 20
|
local finalHeight = math.abs(y) + 20
|
||||||
itemContainer:SetHeight(finalHeight)
|
itemContainer:SetHeight(finalHeight)
|
||||||
self:ResizeFrame(nil, nil, perRow, finalHeight)
|
self:ResizeFrame(nil, nil, perRow, finalHeight)
|
||||||
|
|||||||
@@ -4,6 +4,160 @@ local addon = Guda
|
|||||||
local FrameHelpers = {}
|
local FrameHelpers = {}
|
||||||
addon.Modules.FrameHelpers = FrameHelpers
|
addon.Modules.FrameHelpers = FrameHelpers
|
||||||
|
|
||||||
|
-- Standard category list used by both Bag and Bank frames
|
||||||
|
Guda_CategoryList = {
|
||||||
|
"BoE", "Weapon", "Armor", "Consumable", "Food", "Drink", "Trade Goods", "Reagent", "Recipe", "Quiver", "Container", "Soul Bag", "Miscellaneous", "Quest", "Junk", "Class Items", "Keyring"
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Categorize a single item into categories and specialItems tables
|
||||||
|
-- Returns nothing, modifies tables in place
|
||||||
|
function Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems, isOtherChar)
|
||||||
|
local itemName = itemData.name or ""
|
||||||
|
local itemType = itemData.type or ""
|
||||||
|
local cat = "Miscellaneous"
|
||||||
|
|
||||||
|
-- Detect consumable restore/eat/drink tag for current character only
|
||||||
|
if not isOtherChar and addon.Modules.Utils and addon.Modules.Utils.GetConsumableRestoreTag then
|
||||||
|
local tag = addon.Modules.Utils:GetConsumableRestoreTag(bagID, slotID)
|
||||||
|
if tag then
|
||||||
|
itemData.restoreTag = tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 1: Special items (Hearthstone, Mounts, Tools)
|
||||||
|
if string.find(itemName, "Hearthstone") then
|
||||||
|
table.insert(specialItems.Hearthstone, {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
elseif addon.Modules.SortEngine and addon.Modules.SortEngine.IsMount and addon.Modules.SortEngine.IsMount(itemData.texture) then
|
||||||
|
table.insert(specialItems.Mount, {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
elseif string.find(itemName, "Runed .* Rod") or
|
||||||
|
itemType == "Fishing Pole" or
|
||||||
|
string.find(itemName, "Mining Pick") or
|
||||||
|
string.find(itemName, "Blacksmith Hammer") or
|
||||||
|
itemName == "Arclight Spanner" or
|
||||||
|
itemName == "Gyromatic Micro-Adjustor" or
|
||||||
|
itemName == "Philosopher's Stone" or
|
||||||
|
string.find(itemName, "Skinning Knife") or
|
||||||
|
itemName == "Blood Scythe" then
|
||||||
|
table.insert(specialItems.Tools, {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 2: Class Items (Soul Shards, Arrows, Bullets)
|
||||||
|
if addon.Modules.Utils:IsSoulShard(itemData.link) or
|
||||||
|
itemData.class == "Projectile" or
|
||||||
|
itemData.subclass == "Arrow" or
|
||||||
|
itemData.subclass == "Bullet" then
|
||||||
|
table.insert(categories["Class Items"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 3: Quest Items
|
||||||
|
if (not isOtherChar and addon.Modules.Utils:IsQuestItemTooltip(bagID, slotID)) or itemData.class == "Quest" then
|
||||||
|
table.insert(categories["Quest"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 4: Junk (Gray items)
|
||||||
|
if itemData.quality == 0 or addon.Modules.Utils:IsItemGrayTooltip(bagID, slotID, itemData.link) then
|
||||||
|
table.insert(categories["Junk"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 5: Food and Drink
|
||||||
|
if itemData.class == "Consumable" then
|
||||||
|
cat = "Consumable"
|
||||||
|
local sub = itemData.subclass or ""
|
||||||
|
if sub == "Food & Drink" or string.find(sub, "Food") or string.find(sub, "Drink") then
|
||||||
|
if string.find(sub, "Drink") then
|
||||||
|
cat = "Drink"
|
||||||
|
else
|
||||||
|
cat = "Food"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 6: BoE Equipment (Armor/Weapons that bind when equipped)
|
||||||
|
if (itemData.class == "Weapon" or itemData.class == "Armor") and not isOtherChar then
|
||||||
|
local isBoE = addon.Modules.Utils:IsBindOnEquip(bagID, slotID)
|
||||||
|
if isBoE then
|
||||||
|
table.insert(categories["BoE"], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
else
|
||||||
|
table.insert(categories[itemData.class], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 7: Equipment for other characters (can't scan tooltip)
|
||||||
|
if (itemData.class == "Weapon" or itemData.class == "Armor") and isOtherChar then
|
||||||
|
table.insert(categories[itemData.class], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Priority 8: Other Categories
|
||||||
|
cat = itemData.class or "Miscellaneous"
|
||||||
|
if not categories[cat] then cat = "Miscellaneous" end
|
||||||
|
table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Initialize empty category tables
|
||||||
|
function Guda_InitCategories()
|
||||||
|
local categories = {}
|
||||||
|
for _, cat in ipairs(Guda_CategoryList) do
|
||||||
|
categories[cat] = {}
|
||||||
|
end
|
||||||
|
local specialItems = {
|
||||||
|
Hearthstone = {},
|
||||||
|
Mount = {},
|
||||||
|
Tools = {}
|
||||||
|
}
|
||||||
|
return categories, specialItems
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sort items within a category
|
||||||
|
function Guda_SortCategoryItems(items)
|
||||||
|
table.sort(items, function(a, b)
|
||||||
|
-- Rank Trade Goods: meat (name ends with 'meat') = 2, egg (contains 'egg') = 1, others = 0
|
||||||
|
local function tgRank(d)
|
||||||
|
if not d or not d.name then return 0 end
|
||||||
|
local t = d.type or d.class or ""
|
||||||
|
if t ~= "Trade Goods" then return 0 end
|
||||||
|
local n = string.lower(d.name)
|
||||||
|
if string.find(n, "meat$") then return 2 end
|
||||||
|
if string.find(n, "egg") then return 1 end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
local ra = tgRank(a.itemData)
|
||||||
|
local rb = tgRank(b.itemData)
|
||||||
|
if ra ~= rb then
|
||||||
|
return ra > rb
|
||||||
|
end
|
||||||
|
-- Priority: consumable restore tags (eat > drink > restore > nil)
|
||||||
|
local pa = a.itemData and a.itemData.restoreTag or nil
|
||||||
|
local pb = b.itemData and b.itemData.restoreTag or nil
|
||||||
|
local function pr(t)
|
||||||
|
if t == "eat" then return 3 end
|
||||||
|
if t == "drink" then return 2 end
|
||||||
|
if t == "restore" then return 1 end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
if pr(pa) ~= pr(pb) then
|
||||||
|
return pr(pa) > pr(pb)
|
||||||
|
end
|
||||||
|
-- Fallback: subclass, quality, name
|
||||||
|
if a.itemData.subclass ~= b.itemData.subclass then
|
||||||
|
return (a.itemData.subclass or "") < (b.itemData.subclass or "")
|
||||||
|
end
|
||||||
|
if a.itemData.quality ~= b.itemData.quality then
|
||||||
|
return a.itemData.quality > b.itemData.quality
|
||||||
|
end
|
||||||
|
return (a.itemData.name or "") < (b.itemData.name or "")
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
-- Create or return a section header for a given frame prefix and container
|
-- Create or return a section header for a given frame prefix and container
|
||||||
function Guda_GetSectionHeader(framePrefix, containerName, index)
|
function Guda_GetSectionHeader(framePrefix, containerName, index)
|
||||||
local name = framePrefix .. "_SectionHeader" .. index
|
local name = framePrefix .. "_SectionHeader" .. index
|
||||||
|
|||||||
Reference in New Issue
Block a user