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 @@ + + + + +