feat: adding categories for Guda Bags

This commit is contained in:
Salikh Gurgenidze
2026-01-19 13:11:12 +04:00
parent 8442a70350
commit 29a68d4853
6 changed files with 1102 additions and 17 deletions
+51 -12
View File
@@ -5,10 +5,18 @@ local FrameHelpers = {}
addon.Modules.FrameHelpers = FrameHelpers
-- Standard category list used by both Bag and Bank frames
-- Now dynamically built from CategoryManager if available
Guda_CategoryList = {
"BoE", "Weapon", "Armor", "Consumable", "Food", "Drink", "Trade Goods", "Reagent", "Recipe", "Quiver", "Container", "Soul Bag", "Miscellaneous", "Quest", "Junk", "Class Items", "Keyring"
}
-- Rebuild category list from CategoryManager
function Guda_RefreshCategoryList()
if addon.Modules.CategoryManager then
Guda_CategoryList = addon.Modules.CategoryManager:BuildCategoryList()
end
end
-- Categorize a single item into categories and specialItems tables
-- Returns nothing, modifies tables in place
function Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems, isOtherChar)
@@ -25,6 +33,7 @@ function Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems,
end
-- Priority 1: Special items (Hearthstone, Mounts, Tools)
-- These are handled separately and go into specialItems table, not categories
if string.find(itemName, "Hearthstone") then
table.insert(specialItems.Hearthstone, {bagID = bagID, slotID = slotID, itemData = itemData})
return
@@ -44,22 +53,28 @@ function Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems,
return
end
-- Use CategoryManager rule engine if available, otherwise fall back to legacy logic
if addon.Modules.CategoryManager then
cat = addon.Modules.CategoryManager:CategorizeItem(itemData, bagID, slotID, isOtherChar)
if not categories[cat] then cat = "Miscellaneous" end
table.insert(categories[cat], {bagID = bagID, slotID = slotID, itemData = itemData})
return
end
-- Legacy categorization logic (fallback if CategoryManager not available)
-- Priority 2: Class Items (Soul Shards, Arrows, Bullets)
if addon.Modules.Utils:IsSoulShard(itemData.link) or
itemData.class == "Projectile" or
itemData.subclass == "Arrow" or
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
-- Check multiple sources: tooltip scan, itemClass, itemType, and QuestItemsDB
local isQuestItem = false
local itemCategory = itemData.class or itemData.category or ""
local itemType = itemData.type or ""
-- If it's a Weapon or Armor, it shouldn't be a QuestItem unless it's specifically categorized as Quest
local isEquipment = (itemCategory == "Weapon" or itemCategory == "Armor" or itemType == "Weapon" or itemType == "Armor")
local isQuestCategory = (itemCategory == "Quest" or itemType == "Quest")
@@ -67,12 +82,10 @@ function Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems,
isQuestItem = true
elseif not isOtherChar then
isQuestItem = addon.Modules.Utils:IsQuestItemTooltip(bagID, slotID)
-- If tooltip said it is quest, but it is equipment and not quest category, reject it
if isQuestItem and isEquipment and not isQuestCategory then
isQuestItem = false
end
end
-- Also check the QuestItemsDB for known faction-specific quest items
if not isQuestItem and itemData.link then
local itemID = addon.Modules.Utils:ExtractItemID(itemData.link)
if itemID and addon.IsQuestItemByID then
@@ -106,7 +119,7 @@ function Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems,
return
end
-- Priority 6: BoE Equipment (Armor/Weapons that bind when equipped)
-- Priority 6: BoE Equipment
if (itemData.class == "Weapon" or itemData.class == "Armor") and not isOtherChar then
local isBoE = addon.Modules.Utils:IsBindOnEquip(bagID, slotID, itemData.link)
if isBoE then
@@ -117,7 +130,7 @@ function Guda_CategorizeItem(itemData, bagID, slotID, categories, specialItems,
return
end
-- Priority 7: Equipment for other characters (can't scan tooltip)
-- Priority 7: Equipment for other characters
if (itemData.class == "Weapon" or itemData.class == "Armor") and isOtherChar then
table.insert(categories[itemData.class], {bagID = bagID, slotID = slotID, itemData = itemData})
return
@@ -131,10 +144,36 @@ end
-- Initialize empty category tables
function Guda_InitCategories()
-- Refresh category list from CategoryManager (enabled categories only for display)
Guda_RefreshCategoryList()
-- Create tables for ALL categories (not just enabled) so items can be categorized
-- Items in disabled categories simply won't be displayed
local categories = {}
for _, cat in ipairs(Guda_CategoryList) do
categories[cat] = {}
if addon.Modules.CategoryManager then
-- Get full category order (all categories, not just enabled)
local allCategories = addon.Modules.CategoryManager:GetCategoryOrder()
for _, cat in ipairs(allCategories) do
categories[cat] = {}
end
else
-- Fallback: use the display list
for _, cat in ipairs(Guda_CategoryList) do
categories[cat] = {}
end
end
-- Always ensure Miscellaneous exists as fallback
if not categories["Miscellaneous"] then
categories["Miscellaneous"] = {}
end
-- Always ensure Keyring exists (handled specially in BagFrame)
if not categories["Keyring"] then
categories["Keyring"] = {}
end
local specialItems = {
Hearthstone = {},
Mount = {},
+236
View File
@@ -52,19 +52,23 @@ function Guda_SettingsPopup_SelectTab(tabName)
-- Hide all tab content frames
local generalTab = getglobal("Guda_SettingsPopup_GeneralTab")
local iconsTab = getglobal("Guda_SettingsPopup_IconsTab")
local categoriesTab = getglobal("Guda_SettingsPopup_CategoriesTab")
local guideTab = getglobal("Guda_SettingsPopup_GuideTab")
if generalTab then generalTab:Hide() end
if iconsTab then iconsTab:Hide() end
if categoriesTab then categoriesTab:Hide() end
if guideTab then guideTab:Hide() end
-- Reset all tab button backgrounds to inactive (0.1 alpha)
local generalBg = getglobal("Guda_SettingsPopup_GeneralTabButton_Bg")
local iconsBg = getglobal("Guda_SettingsPopup_IconsTabButton_Bg")
local categoriesBg = getglobal("Guda_SettingsPopup_CategoriesTabButton_Bg")
local guideBg = getglobal("Guda_SettingsPopup_GuideTabButton_Bg")
if generalBg then generalBg:SetTexture(1, 1, 1, 0.1) end
if iconsBg then iconsBg:SetTexture(1, 1, 1, 0.1) end
if categoriesBg then categoriesBg:SetTexture(1, 1, 1, 0.1) end
if guideBg then guideBg:SetTexture(1, 1, 1, 0.1) end
-- Show selected tab and highlight its button
@@ -74,6 +78,10 @@ function Guda_SettingsPopup_SelectTab(tabName)
elseif tabName == "icons" then
if iconsTab then iconsTab:Show() end
if iconsBg then iconsBg:SetTexture(1, 1, 1, 0.3) end
elseif tabName == "categories" then
if categoriesTab then categoriesTab:Show() end
if categoriesBg then categoriesBg:SetTexture(1, 1, 1, 0.3) end
Guda_SettingsPopup_CategoriesTab_Update()
elseif tabName == "guide" then
if guideTab then guideTab:Show() end
if guideBg then guideBg:SetTexture(1, 1, 1, 0.3) end
@@ -1160,6 +1168,234 @@ function Guda_SettingsPopup_ReverseStackSortCheckbox_OnClick(self)
-- No immediate UI update needed
end
-------------------------------------------
-- Categories Tab Functions
-------------------------------------------
-- Number of visible rows in the category list
local CATEGORY_ROW_HEIGHT = 22
local CATEGORY_VISIBLE_ROWS = 14
local categoryRowFrames = {}
-- Create or get a category row frame
local function GetCategoryRowFrame(index)
if categoryRowFrames[index] then
return categoryRowFrames[index]
end
local container = getglobal("Guda_SettingsPopup_CategoryListContainer")
if not container then return nil end
local rowName = "Guda_SettingsPopup_CategoryRow" .. index
local row = CreateFrame("Frame", rowName, container)
row:SetHeight(CATEGORY_ROW_HEIGHT)
row:SetWidth(420)
row:SetPoint("TOPLEFT", container, "TOPLEFT", 0, -((index - 1) * CATEGORY_ROW_HEIGHT))
-- Background highlight
local bg = row:CreateTexture(nil, "BACKGROUND")
bg:SetAllPoints(row)
bg:SetTexture(1, 1, 1, 0)
row.bg = bg
-- Enable checkbox
local checkbox = CreateFrame("CheckButton", rowName .. "_Checkbox", row, "UICheckButtonTemplate")
checkbox:SetWidth(20)
checkbox:SetHeight(20)
checkbox:SetPoint("LEFT", row, "LEFT", 0, 0)
checkbox:SetScript("OnClick", function()
local catId = this:GetParent().categoryId
if catId and Guda.Modules.CategoryManager then
Guda.Modules.CategoryManager:ToggleCategory(catId)
Guda_SettingsPopup_CategoriesTab_Update()
Guda_SettingsPopup_RefreshBagFrames()
end
end)
row.checkbox = checkbox
-- Category name
local nameText = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
nameText:SetPoint("LEFT", checkbox, "RIGHT", 5, 0)
nameText:SetWidth(200)
nameText:SetJustifyH("LEFT")
row.nameText = nameText
-- Move Up button
local upBtn = CreateFrame("Button", rowName .. "_UpBtn", row)
upBtn:SetWidth(20)
upBtn:SetHeight(20)
upBtn:SetPoint("LEFT", nameText, "RIGHT", 10, 0)
upBtn:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Up")
upBtn:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Down")
upBtn:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollUpButton-Highlight")
upBtn:SetScript("OnClick", function()
local catId = this:GetParent().categoryId
if catId and Guda.Modules.CategoryManager then
Guda.Modules.CategoryManager:MoveCategoryUp(catId)
Guda_SettingsPopup_CategoriesTab_Update()
Guda_SettingsPopup_RefreshBagFrames()
end
end)
row.upBtn = upBtn
-- Move Down button
local downBtn = CreateFrame("Button", rowName .. "_DownBtn", row)
downBtn:SetWidth(20)
downBtn:SetHeight(20)
downBtn:SetPoint("LEFT", upBtn, "RIGHT", 2, 0)
downBtn:SetNormalTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Up")
downBtn:SetPushedTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Down")
downBtn:SetHighlightTexture("Interface\\Buttons\\UI-ScrollBar-ScrollDownButton-Highlight")
downBtn:SetScript("OnClick", function()
local catId = this:GetParent().categoryId
if catId and Guda.Modules.CategoryManager then
Guda.Modules.CategoryManager:MoveCategoryDown(catId)
Guda_SettingsPopup_CategoriesTab_Update()
Guda_SettingsPopup_RefreshBagFrames()
end
end)
row.downBtn = downBtn
-- Delete button (only for custom categories)
local deleteBtn = CreateFrame("Button", rowName .. "_DeleteBtn", row, "UIPanelCloseButton")
deleteBtn:SetWidth(20)
deleteBtn:SetHeight(20)
deleteBtn:SetPoint("LEFT", downBtn, "RIGHT", 5, 0)
deleteBtn:SetScript("OnClick", function()
local catId = this:GetParent().categoryId
if catId and Guda.Modules.CategoryManager then
local def = Guda.Modules.CategoryManager:GetCategory(catId)
if def and not def.isBuiltIn then
Guda.Modules.CategoryManager:DeleteCategory(catId)
Guda_SettingsPopup_CategoriesTab_Update()
Guda_SettingsPopup_RefreshBagFrames()
end
end
end)
row.deleteBtn = deleteBtn
-- Built-in indicator
local builtInText = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
builtInText:SetPoint("LEFT", deleteBtn, "RIGHT", 5, 0)
builtInText:SetText("(Built-in)")
builtInText:SetTextColor(0.5, 0.5, 0.5)
row.builtInText = builtInText
-- Hover highlight
row:EnableMouse(true)
row:SetScript("OnEnter", function()
this.bg:SetTexture(1, 1, 1, 0.1)
end)
row:SetScript("OnLeave", function()
this.bg:SetTexture(1, 1, 1, 0)
end)
categoryRowFrames[index] = row
return row
end
-- Update the category list display
function Guda_SettingsPopup_CategoriesTab_Update()
if not Guda.Modules.CategoryManager then return end
local scrollFrame = getglobal("Guda_SettingsPopup_CategoriesScrollFrame")
if not scrollFrame then return end
local categoryOrder = Guda.Modules.CategoryManager:GetCategoryOrder()
local totalCategories = table.getn(categoryOrder)
-- Update scroll frame
FauxScrollFrame_Update(scrollFrame, totalCategories, CATEGORY_VISIBLE_ROWS, CATEGORY_ROW_HEIGHT)
local offset = FauxScrollFrame_GetOffset(scrollFrame)
for i = 1, CATEGORY_VISIBLE_ROWS do
local row = GetCategoryRowFrame(i)
if row then
local dataIndex = i + offset
if dataIndex <= totalCategories then
local categoryId = categoryOrder[dataIndex]
local categoryDef = Guda.Modules.CategoryManager:GetCategory(categoryId)
if categoryDef then
row.categoryId = categoryId
row.nameText:SetText(categoryDef.name or categoryId)
row.checkbox:SetChecked(categoryDef.enabled and 1 or 0)
-- Show/hide delete button based on whether it's built-in
if categoryDef.isBuiltIn then
row.deleteBtn:Hide()
row.builtInText:Show()
else
row.deleteBtn:Show()
row.builtInText:Hide()
end
-- Enable/disable move buttons based on position
if dataIndex == 1 then
row.upBtn:Disable()
else
row.upBtn:Enable()
end
if dataIndex == totalCategories then
row.downBtn:Disable()
else
row.downBtn:Enable()
end
-- Set text color based on enabled state
if categoryDef.enabled then
row.nameText:SetTextColor(1, 1, 1)
else
row.nameText:SetTextColor(0.5, 0.5, 0.5)
end
row:Show()
else
row:Hide()
end
else
row:Hide()
end
end
end
-- Set reset button text
local resetBtn = getglobal("Guda_SettingsPopup_ResetCategoriesButton")
if resetBtn then
resetBtn:SetText("Reset to Defaults")
end
end
-- Reset categories to defaults
function Guda_SettingsPopup_ResetCategories_OnClick()
if Guda.Modules.CategoryManager then
Guda.Modules.CategoryManager:ResetToDefaults()
Guda_SettingsPopup_CategoriesTab_Update()
Guda_SettingsPopup_RefreshBagFrames()
Guda:Print("Categories reset to defaults.")
end
end
-- Refresh bag and bank frames after category changes
function Guda_SettingsPopup_RefreshBagFrames()
-- Refresh category list
Guda_RefreshCategoryList()
-- Update bag frame if visible
local bagFrame = getglobal("Guda_BagFrame")
if bagFrame and bagFrame:IsShown() then
Guda.Modules.BagFrame:Update()
end
-- Update bank frame if visible
local bankFrame = getglobal("Guda_BankFrame")
if bankFrame and bankFrame:IsShown() then
Guda.Modules.BankFrame:Update()
end
end
-- Initialize
function SettingsPopup:Initialize()
Guda:Debug("Settings popup initialized")
+123 -5
View File
@@ -62,7 +62,7 @@
<!-- Tab Buttons (GudaPlates style) -->
<Button name="Guda_SettingsPopup_GeneralTabButton" enableMouse="true">
<Size>
<AbsDimension x="150" y="28"/>
<AbsDimension x="113" y="28"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parent" relativePoint="TOPLEFT">
@@ -94,7 +94,7 @@
<Button name="Guda_SettingsPopup_IconsTabButton" enableMouse="true">
<Size>
<AbsDimension x="150" y="28"/>
<AbsDimension x="113" y="28"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="Guda_SettingsPopup_GeneralTabButton" relativePoint="RIGHT">
@@ -124,9 +124,9 @@
</Scripts>
</Button>
<Button name="Guda_SettingsPopup_GuideTabButton" enableMouse="true">
<Button name="Guda_SettingsPopup_CategoriesTabButton" enableMouse="true">
<Size>
<AbsDimension x="150" y="28"/>
<AbsDimension x="113" y="28"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="Guda_SettingsPopup_IconsTabButton" relativePoint="RIGHT">
@@ -142,7 +142,39 @@
</Texture>
</Layer>
<Layer level="OVERLAY">
<FontString name="$parent_Text" inherits="GameFontNormal" text="Quick Guide">
<FontString name="$parent_Text" inherits="GameFontNormal" text="Categories">
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnClick>
Guda_SettingsPopup_SelectTab("categories")
</OnClick>
</Scripts>
</Button>
<Button name="Guda_SettingsPopup_GuideTabButton" enableMouse="true">
<Size>
<AbsDimension x="113" y="28"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="Guda_SettingsPopup_CategoriesTabButton" relativePoint="RIGHT">
<Offset>
<AbsDimension x="2" y="0"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parent_Bg" setAllPoints="true">
<Color r="1" g="1" b="1" a="0.1"/>
</Texture>
</Layer>
<Layer level="OVERLAY">
<FontString name="$parent_Text" inherits="GameFontNormal" text="Guide">
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
@@ -600,6 +632,92 @@
</Frames>
</Frame>
<!-- Categories Tab Content -->
<Frame name="Guda_SettingsPopup_CategoriesTab" hidden="true">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parent" relativePoint="TOPLEFT">
<Offset>
<AbsDimension x="15" y="-90"/>
</Offset>
</Anchor>
<Anchor point="BOTTOMRIGHT" relativeTo="$parent" relativePoint="BOTTOMRIGHT">
<Offset>
<AbsDimension x="-15" y="15"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<FontString name="$parent_Header" inherits="GameFontNormal" text="Manage item categories and their display order:">
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="5" y="-5"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<!-- Scroll Frame for Category List -->
<ScrollFrame name="Guda_SettingsPopup_CategoriesScrollFrame" inherits="FauxScrollFrameTemplate">
<Size>
<AbsDimension x="440" y="320"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="5" y="-25"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnVerticalScroll>
FauxScrollFrame_OnVerticalScroll(18, Guda_SettingsPopup_CategoriesTab_Update)
</OnVerticalScroll>
<OnShow>
Guda_SettingsPopup_CategoriesTab_Update()
</OnShow>
</Scripts>
</ScrollFrame>
<!-- Category Row Container -->
<Frame name="Guda_SettingsPopup_CategoryListContainer">
<Size>
<AbsDimension x="420" y="320"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="Guda_SettingsPopup_CategoriesScrollFrame" relativePoint="TOPLEFT"/>
</Anchors>
</Frame>
<!-- Reset to Defaults Button -->
<Button name="Guda_SettingsPopup_ResetCategoriesButton" inherits="UIPanelButtonTemplate">
<Size>
<AbsDimension x="140" y="25"/>
</Size>
<Anchors>
<Anchor point="BOTTOMLEFT" relativeTo="$parent" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="5" y="10"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Guda_SettingsPopup_ResetCategories_OnClick()
</OnClick>
</Scripts>
<NormalText>
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
</NormalText>
</Button>
</Frames>
</Frame>
<!-- Guide Tab Content -->
<Frame name="Guda_SettingsPopup_GuideTab" hidden="true">
<Anchors>