diff --git a/Core/Database.lua b/Core/Database.lua
index 0bdebcf..533b830 100644
--- a/Core/Database.lua
+++ b/Core/Database.lua
@@ -47,12 +47,20 @@ function DB:Initialize()
bgTransparency = 0.15,
showTrackedItems = true,
showTooltipCounts = true,
+ bagViewType = "single", -- single, category
+ bankViewType = "single", -- single, category
trackedItems = {},
},
}
end
-- Ensure new settings exist for existing installations
+ if Guda_CharDB.settings.bagViewType == nil then
+ Guda_CharDB.settings.bagViewType = "single"
+ end
+ if Guda_CharDB.settings.bankViewType == nil then
+ Guda_CharDB.settings.bankViewType = "single"
+ end
if Guda_CharDB.settings.showTooltipCounts == nil then
Guda_CharDB.settings.showTooltipCounts = true
end
diff --git a/UI/BagFrame.lua b/UI/BagFrame.lua
index 1032ade..a1606fc 100644
--- a/UI/BagFrame.lua
+++ b/UI/BagFrame.lua
@@ -322,7 +322,12 @@ function BagFrame:Update()
end
-- Display items
- self:DisplayItems(bagData, isOtherChar, charName)
+ local viewType = addon.Modules.DB:GetSetting("bagViewType") or "single"
+ if viewType == "category" then
+ self:DisplayItemsByCategory(bagData, isOtherChar, charName)
+ else
+ self:DisplayItems(bagData, isOtherChar, charName)
+ end
-- Update money
self:UpdateMoney()
@@ -330,9 +335,20 @@ function BagFrame:Update()
-- Update bag slots info
self:UpdateBagSlotsInfo(bagData, isOtherChar)
- -- Update bagline layout (hover option)
+ -- Update bagline layout (hover option)
self:UpdateBaglineLayout()
+ -- Clean up unused section headers
+ local i = 1
+ while true do
+ local header = getglobal("Guda_BagFrame_SectionHeader" .. i)
+ if not header then break end
+ if not header.inUse then
+ header:Hide()
+ end
+ i = i + 1
+ end
+
-- Clean up unused buttons AFTER display is complete (prevents drag/drop issues)
for _, bagParent in pairs(bagParents) do
if bagParent then
@@ -347,6 +363,157 @@ function BagFrame:Update()
end
end
+-- Helper to get or create section header
+function BagFrame:GetSectionHeader(index)
+ local name = "Guda_BagFrame_SectionHeader" .. index
+ local header = getglobal(name)
+ if not header then
+ header = CreateFrame("Frame", name, getglobal("Guda_BagFrame_ItemContainer"))
+ header:SetHeight(20)
+ local text = header:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ text:SetPoint("LEFT", header, "LEFT", 5, 0)
+ header.text = text
+ end
+ header.inUse = true
+ return header
+end
+
+-- Helper to get or create bag parent frame
+function BagFrame:GetBagParent(bagID)
+ local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
+ if not bagParents[bagID] then
+ bagParents[bagID] = CreateFrame("Frame", "Guda_BagFrame_BagParent"..bagID, itemContainer)
+ bagParents[bagID]:SetAllPoints(itemContainer)
+ if bagParents[bagID].SetID then
+ bagParents[bagID]:SetID(bagID)
+ end
+ end
+ return bagParents[bagID]
+end
+
+-- Display items by category
+function BagFrame:DisplayItemsByCategory(bagData, isOtherChar, charName)
+ local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
+ local spacing = addon.Modules.DB:GetSetting("iconSpacing") or addon.Constants.BUTTON_SPACING
+ local perRow = addon.Modules.DB:GetSetting("bagColumns") or 10
+ local itemContainer = getglobal("Guda_BagFrame_ItemContainer")
+
+ -- Reset headers
+ local idx = 1
+ while true do
+ local h = getglobal("Guda_BagFrame_SectionHeader" .. idx)
+ if not h then break end
+ h.inUse = false
+ idx = idx + 1
+ end
+
+ -- Group items by category
+ local categories = {}
+ local categoryList = {
+ "Equipment", "Consumable", "Quest", "Trade Goods", "Reagent", "Recipe", "Quiver", "Container", "Miscellaneous", "Soul Bag", "Keyring"
+ }
+ for _, cat in ipairs(categoryList) do categories[cat] = {} end
+
+ for _, bagID in ipairs(addon.Constants.BAGS) do
+ if not hiddenBags[bagID] then
+ local bag = bagData[bagID]
+ if bag and bag.slots then
+ for slotID, itemData in pairs(bag.slots) do
+ if itemData then
+ local cat = itemData.class or "Miscellaneous"
+ -- Special handling for equipment
+ if itemData.equipSlot and itemData.equipSlot ~= "" then
+ cat = "Equipment"
+ end
+ if not categories[cat] then categories[cat] = {} end
+ table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
+ end
+ end
+ end
+ end
+ end
+
+ -- Handle Keyring if visible
+ if showKeyring and not hiddenBags[-2] then
+ local bag = bagData[-2]
+ if bag and bag.slots then
+ for slotID, itemData in pairs(bag.slots) do
+ if itemData then
+ table.insert(categories["Keyring"], {bagID = -2, slotID = slotID, itemData = itemData})
+ end
+ end
+ end
+ end
+
+ -- Layout
+ local x, y = 10, -10
+ local headerIdx = 1
+ local totalHeight = 20
+
+ for _, catName in ipairs(categoryList) do
+ local items = categories[catName]
+ if items and table.getn(items) > 0 then
+ -- Sort items in category
+ table.sort(items, function(a, b)
+ 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)
+
+ -- Add Header
+ local header = self:GetSectionHeader(headerIdx)
+ headerIdx = headerIdx + 1
+ header:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", 0, y)
+ header:SetWidth(perRow * (buttonSize + spacing))
+ header.text:SetText(catName)
+ header:Show()
+
+ y = y - 20
+
+ local col = 0
+ for _, item in ipairs(items) do
+ local bagID = item.bagID
+ local slot = item.slotID
+ local itemData = item.itemData
+
+ local bagParent = self:GetBagParent(bagID)
+ local button = Guda_GetItemButton(bagParent)
+
+ button:SetParent(bagParent)
+ button:SetWidth(buttonSize)
+ button:SetHeight(buttonSize)
+ button:ClearAllPoints()
+ button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", x + (col * (buttonSize + spacing)), y)
+ button:Show()
+
+ local matchesFilter = true
+ if searchText ~= "" then
+ matchesFilter = BagFrame:MatchesSearch(itemData, searchText)
+ end
+
+ Guda_ItemButton_SetItem(button, bagID, slot, itemData, false, isOtherChar and charName or nil, matchesFilter, true)
+ button.inUse = true
+
+ col = col + 1
+ if col >= perRow then
+ col = 0
+ y = y - (buttonSize + spacing)
+ end
+ end
+
+ if col > 0 then
+ y = y - (buttonSize + spacing)
+ end
+ y = y - 5 -- Padding between sections
+ end
+ end
+
+ -- Update container height
+ itemContainer:SetHeight(math.abs(y) + 20)
+ self:UpdateFrameSize()
+end
+
-- Display items
function BagFrame:DisplayItems(bagData, isOtherChar, charName)
local x, y = 10, -10
@@ -465,17 +632,7 @@ function BagFrame:DisplayItems(bagData, isOtherChar, charName)
if numSlots and numSlots > 0 then
-- Iterate through ALL slots (1 to numSlots) to show empty slots too
-- Ensure a per-bag parent frame exists and carries the bag ID (Blizzard expects parent:GetID() == bagID)
- local bagParent
- do
- if not bagParents[bagID] then
- bagParents[bagID] = CreateFrame("Frame", "Guda_BagFrame_BagParent"..bagID, itemContainer)
- bagParents[bagID]:SetAllPoints(itemContainer)
- if bagParents[bagID].SetID then
- bagParents[bagID]:SetID(bagID)
- end
- end
- bagParent = bagParents[bagID]
- end
+ local bagParent = self:GetBagParent(bagID)
for slot = 1, numSlots do
local itemData = bag and bag.slots and bag.slots[slot] or nil
diff --git a/UI/BankFrame.lua b/UI/BankFrame.lua
index 4fe30f3..793891a 100644
--- a/UI/BankFrame.lua
+++ b/UI/BankFrame.lua
@@ -177,7 +177,12 @@ function BankFrame:Update()
end
end
- self:DisplayItems(bankData, isOtherChar, charName)
+ local viewType = addon.Modules.DB:GetSetting("bankViewType") or "single"
+ if viewType == "category" then
+ self:DisplayItemsByCategory(bankData, isOtherChar, charName)
+ else
+ self:DisplayItems(bankData, isOtherChar, charName)
+ end
-- Update money
self:UpdateMoney()
@@ -185,6 +190,17 @@ function BankFrame:Update()
-- Update bank slots info
self:UpdateBankSlotsInfo(bankData, isOtherChar)
+ -- Clean up unused section headers
+ local i = 1
+ while true do
+ local header = getglobal("Guda_BankFrame_SectionHeader" .. i)
+ if not header then break end
+ if not header.inUse then
+ header:Hide()
+ end
+ i = i + 1
+ end
+
-- Clean up unused buttons AFTER display is complete (prevents drag/drop issues)
for _, bankBagParent in pairs(bankBagParents) do
if bankBagParent then
@@ -199,6 +215,152 @@ function BankFrame:Update()
end
end
+-- Helper to get or create section header
+function BankFrame:GetSectionHeader(index)
+ local name = "Guda_BankFrame_SectionHeader" .. index
+ local header = getglobal(name)
+ if not header then
+ header = CreateFrame("Frame", name, getglobal("Guda_BankFrame_ItemContainer"))
+ header:SetHeight(20)
+ local text = header:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ text:SetPoint("LEFT", header, "LEFT", 5, 0)
+ header.text = text
+ end
+ header.inUse = true
+ return header
+end
+
+-- Helper to get or create bank bag parent frame
+function BankFrame:GetBagParent(bagID)
+ local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
+ if not bankBagParents[bagID] then
+ bankBagParents[bagID] = CreateFrame("Frame", "Guda_BankFrame_BagParent"..bagID, itemContainer)
+ bankBagParents[bagID]:SetAllPoints(itemContainer)
+ if bankBagParents[bagID].SetID then
+ bankBagParents[bagID]:SetID(bagID)
+ end
+ end
+ return bankBagParents[bagID]
+end
+
+-- Display items by category
+function BankFrame:DisplayItemsByCategory(bankData, isOtherChar, charName)
+ local buttonSize = addon.Modules.DB:GetSetting("iconSize") or addon.Constants.BUTTON_SIZE
+ local spacing = addon.Modules.DB:GetSetting("iconSpacing") or addon.Constants.BUTTON_SPACING
+ local perRow = addon.Modules.DB:GetSetting("bankColumns") or 10
+ local itemContainer = getglobal("Guda_BankFrame_ItemContainer")
+
+ -- Reset headers
+ local idx = 1
+ while true do
+ local h = getglobal("Guda_BankFrame_SectionHeader" .. idx)
+ if not h then break end
+ h.inUse = false
+ idx = idx + 1
+ end
+
+ -- Group items by category
+ local categories = {}
+ local categoryList = {
+ "Equipment", "Consumable", "Quest", "Trade Goods", "Reagent", "Recipe", "Quiver", "Container", "Miscellaneous"
+ }
+ for _, cat in ipairs(categoryList) do categories[cat] = {} end
+
+ -- Bank main slots (bagID -1)
+ local bankMain = bankData[-1]
+ if bankMain and bankMain.slots then
+ for slotID, itemData in pairs(bankMain.slots) do
+ if itemData then
+ local cat = itemData.class or "Miscellaneous"
+ if itemData.equipSlot and itemData.equipSlot ~= "" then cat = "Equipment" end
+ if not categories[cat] then categories[cat] = {} end
+ table.insert(categories[cat], {bagID = -1, slotID = slotID, itemData = itemData})
+ end
+ end
+ end
+
+ -- Bank bags
+ for _, bagID in ipairs(addon.Constants.BANK_BAGS) do
+ if not hiddenBankBags[bagID] then
+ local bag = bankData[bagID]
+ if bag and bag.slots then
+ for slotID, itemData in pairs(bag.slots) do
+ if itemData then
+ local cat = itemData.class or "Miscellaneous"
+ if itemData.equipSlot and itemData.equipSlot ~= "" then cat = "Equipment" end
+ if not categories[cat] then categories[cat] = {} end
+ table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
+ end
+ end
+ end
+ end
+ end
+
+ -- Layout
+ local x, y = 5, -10
+ local headerIdx = 1
+
+ for _, catName in ipairs(categoryList) do
+ local items = categories[catName]
+ if items and table.getn(items) > 0 then
+ -- Sort items in category
+ table.sort(items, function(a, b)
+ 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)
+
+ -- Add Header
+ local header = self:GetSectionHeader(headerIdx)
+ headerIdx = headerIdx + 1
+ header:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", 0, y)
+ header:SetWidth(perRow * (buttonSize + spacing))
+ header.text:SetText(catName)
+ header:Show()
+
+ y = y - 20
+
+ local col = 0
+ for _, item in ipairs(items) do
+ local bagID = item.bagID
+ local slot = item.slotID
+ local itemData = item.itemData
+
+ local bagParent = self:GetBagParent(bagID)
+ local button = Guda_GetItemButton(bagParent)
+
+ button:SetParent(bagParent)
+ button:SetWidth(buttonSize)
+ button:SetHeight(buttonSize)
+ button:ClearAllPoints()
+ button:SetPoint("TOPLEFT", itemContainer, "TOPLEFT", x + (col * (buttonSize + spacing)), y)
+ button:Show()
+
+ local matchesFilter = self:PassesSearchFilter(itemData)
+
+ Guda_ItemButton_SetItem(button, bagID, slot, itemData, true, isOtherChar and charName or nil, matchesFilter, true)
+ button.inUse = true
+
+ col = col + 1
+ if col >= perRow then
+ col = 0
+ y = y - (buttonSize + spacing)
+ end
+ end
+
+ if col > 0 then
+ y = y - (buttonSize + spacing)
+ end
+ y = y - 5 -- Padding between sections
+ end
+ end
+
+ -- Update container height
+ itemContainer:SetHeight(math.abs(y) + 20)
+ self:UpdateFrameSize()
+end
+
-- Display items
function BankFrame:DisplayItems(bankData, isOtherChar, charName)
local x, y = 5, -10
@@ -304,15 +466,7 @@ function BankFrame:DisplayItems(bankData, isOtherChar, charName)
local matchesFilter = self:PassesSearchFilter(itemData)
-- Ensure a per-bag parent frame exists and carries the bag ID
- local bankBagParent
- if not bankBagParents[bagID] then
- bankBagParents[bagID] = CreateFrame("Frame", "Guda_BankFrame_BankBagParent"..bagID, itemContainer)
- bankBagParents[bagID]:SetAllPoints(itemContainer)
- if bankBagParents[bagID].SetID then
- bankBagParents[bagID]:SetID(bagID)
- end
- end
- bankBagParent = bankBagParents[bagID]
+ local bankBagParent = self:GetBagParent(bagID)
local button = Guda_GetItemButton(bankBagParent)
if button.isBagSlot then break end
@@ -854,14 +1008,16 @@ function BankFrame:EnsureBagButtonsInitialized()
btn = CreateFrame("Button", name, toolbar, "ItemButtonTemplate")
-- Anchor sequenced to the left; position similar to XML
if suffix == "BankBagMain" then
- btn:SetSize(24, 24)
+ btn:SetWidth(24)
+ btn:SetHeight(24)
btn:SetPoint("LEFT", toolbar, "LEFT", 13, 0)
else
-- Determine previous button
local prev
if bagID == 5 then prev = getglobal("Guda_BankFrame_Toolbar_BankBagMain")
else prev = getglobal("Guda_BankFrame_Toolbar_BankBag"..tostring(bagID-1)) end
- btn:SetSize(24, 24)
+ btn:SetWidth(24)
+ btn:SetHeight(24)
if prev then
btn:SetPoint("LEFT", prev, "RIGHT", 2, 0)
else
diff --git a/UI/SettingsPopup.lua b/UI/SettingsPopup.lua
index f49f8ba..076d209 100644
--- a/UI/SettingsPopup.lua
+++ b/UI/SettingsPopup.lua
@@ -107,6 +107,8 @@ function Guda_SettingsPopup_OnShow(self)
hoverBagline = false
end
local bgTransparency = Guda.Modules.DB:GetSetting("bgTransparency") or 0.15
+ local bagViewType = Guda.Modules.DB:GetSetting("bagViewType") or "single"
+ local bankViewType = Guda.Modules.DB:GetSetting("bankViewType") or "single"
-- Update sliders and checkboxes
local bagSlider = getglobal("Guda_SettingsPopup_BagColumnsSlider")
@@ -124,6 +126,8 @@ function Guda_SettingsPopup_OnShow(self)
local hoverBaglineCheckbox = getglobal("Guda_SettingsPopup_HoverBaglineCheckbox")
local hideFooterCheckbox = getglobal("Guda_SettingsPopup_HideFooterCheckbox")
local showTooltipCountsCheckbox = getglobal("Guda_SettingsPopup_ShowTooltipCountsCheckbox")
+ local bagViewButton = getglobal("Guda_SettingsPopup_BagViewTypeButton")
+ local bankViewButton = getglobal("Guda_SettingsPopup_BankViewTypeButton")
local showTooltipCounts = Guda.Modules.DB:GetSetting("showTooltipCounts")
if showTooltipCounts == nil then
@@ -186,6 +190,22 @@ function Guda_SettingsPopup_OnShow(self)
showTooltipCountsCheckbox:SetChecked(showTooltipCounts and 1 or 0)
end
+ if bagViewButton then
+ if bagViewType == "single" then
+ bagViewButton:SetText("Bag View: Single")
+ else
+ bagViewButton:SetText("Bag View: Category")
+ end
+ end
+
+ if bankViewButton then
+ if bankViewType == "single" then
+ bankViewButton:SetText("Bank View: Single")
+ else
+ bankViewButton:SetText("Bank View: Category")
+ end
+ end
+
-- Update display (might be too tall for current frame size)
local frame = getglobal("Guda_SettingsPopup")
@@ -919,6 +939,40 @@ function Guda_SettingsPopup_ShowTooltipCountsCheckbox_OnClick(self)
end
end
+-- Bag View Type Button OnClick
+function Guda_SettingsPopup_BagViewTypeButton_OnClick()
+ local current = Guda.Modules.DB:GetSetting("bagViewType") or "single"
+ local newValue = (current == "single") and "category" or "single"
+ Guda.Modules.DB:SetSetting("bagViewType", newValue)
+
+ local btn = getglobal("Guda_SettingsPopup_BagViewTypeButton")
+ if btn then
+ btn:SetText(newValue == "single" and "Bag View: Single" or "Bag View: Category")
+ end
+
+ -- Refresh bag frame if it's open
+ if Guda_BagFrame:IsShown() then
+ Guda.Modules.BagFrame:Update()
+ end
+end
+
+-- Bank View Type Button OnClick
+function Guda_SettingsPopup_BankViewTypeButton_OnClick()
+ local current = Guda.Modules.DB:GetSetting("bankViewType") or "single"
+ local newValue = (current == "single") and "category" or "single"
+ Guda.Modules.DB:SetSetting("bankViewType", newValue)
+
+ local btn = getglobal("Guda_SettingsPopup_BankViewTypeButton")
+ if btn then
+ btn:SetText(newValue == "single" and "Bank View: Single" or "Bank View: Category")
+ end
+
+ -- Refresh bank frame if it's open
+ if Guda_BankFrame:IsShown() then
+ Guda.Modules.BankFrame:Update()
+ end
+end
+
-- Initialize
function SettingsPopup:Initialize()
Guda:Debug("Settings popup initialized")
diff --git a/UI/SettingsPopup.xml b/UI/SettingsPopup.xml
index d75bd29..d6c9f6f 100644
--- a/UI/SettingsPopup.xml
+++ b/UI/SettingsPopup.xml
@@ -394,6 +394,31 @@
+
+
+
+
+