feat: update categories and item slots
This commit is contained in:
+566
-20
@@ -52,13 +52,21 @@ end
|
||||
-- texturePattern: Match icon texture path
|
||||
-- itemID: Specific item IDs (table of IDs)
|
||||
|
||||
-- Group constants
|
||||
local GROUP_MAIN = "Main"
|
||||
local GROUP_OTHER = "Other"
|
||||
local GROUP_CLASS = "Class"
|
||||
|
||||
-- Default category definitions that replicate the existing hardcoded behavior
|
||||
local DEFAULT_CATEGORIES = {
|
||||
order = {
|
||||
"Home", "BoE", "Weapon", "Armor", "Consumable", "Food", "Drink",
|
||||
"BoE", "Weapon", "Armor", "Consumable", "Food", "Drink",
|
||||
"Trade Goods", "Reagent", "Recipe", "Quiver", "Container",
|
||||
"Soul Bag", "Miscellaneous", "Quest", "Junk", "Class Items", "Keyring"
|
||||
"Soul Bag", "Miscellaneous", "Quest", "Junk",
|
||||
"Class Items", "Keyring",
|
||||
"Home", "Tools", "Empty"
|
||||
},
|
||||
itemOverrides = {}, -- flat map: [itemID] = categoryId
|
||||
definitions = {
|
||||
["BoE"] = {
|
||||
name = "BoE",
|
||||
@@ -70,6 +78,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 75,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Weapon"] = {
|
||||
name = "Weapon",
|
||||
@@ -81,6 +90,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 70,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Armor"] = {
|
||||
name = "Armor",
|
||||
@@ -92,6 +102,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 70,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Consumable"] = {
|
||||
name = "Consumable",
|
||||
@@ -103,6 +114,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 50,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Food"] = {
|
||||
name = "Food",
|
||||
@@ -115,6 +127,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 55,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Drink"] = {
|
||||
name = "Drink",
|
||||
@@ -127,6 +140,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 55,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Trade Goods"] = {
|
||||
name = "Trade Goods",
|
||||
@@ -138,6 +152,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 40,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Reagent"] = {
|
||||
name = "Reagent",
|
||||
@@ -149,6 +164,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 40,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Recipe"] = {
|
||||
name = "Recipe",
|
||||
@@ -160,6 +176,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 40,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Quiver"] = {
|
||||
name = "Quiver",
|
||||
@@ -171,6 +188,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 40,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Container"] = {
|
||||
name = "Container",
|
||||
@@ -182,6 +200,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 40,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Soul Bag"] = {
|
||||
name = "Soul Bag",
|
||||
@@ -193,6 +212,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 45,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Miscellaneous"] = {
|
||||
name = "Miscellaneous",
|
||||
@@ -203,6 +223,7 @@ local DEFAULT_CATEGORIES = {
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
isFallback = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Quest"] = {
|
||||
name = "Quest",
|
||||
@@ -214,6 +235,7 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 80,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Junk"] = {
|
||||
name = "Junk",
|
||||
@@ -225,17 +247,20 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 85,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_MAIN,
|
||||
},
|
||||
["Class Items"] = {
|
||||
name = "Class Items",
|
||||
icon = "Interface\\Icons\\INV_Misc_Ammo_Arrow_01",
|
||||
rules = {
|
||||
{ type = "itemType", value = "Projectile" }
|
||||
{ type = "itemType", value = "Projectile" },
|
||||
{ type = "isSoulShard", value = true }
|
||||
},
|
||||
matchMode = "any",
|
||||
priority = 90,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_CLASS,
|
||||
},
|
||||
["Keyring"] = {
|
||||
name = "Keyring",
|
||||
@@ -247,20 +272,56 @@ local DEFAULT_CATEGORIES = {
|
||||
priority = 40,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_CLASS,
|
||||
},
|
||||
["Home"] = {
|
||||
name = "Home",
|
||||
icon = "Interface\\Icons\\INV_Misc_Rune_01",
|
||||
rules = {
|
||||
{ type = "itemID", value = {6948} }
|
||||
},
|
||||
matchMode = "all",
|
||||
priority = 100,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_OTHER,
|
||||
},
|
||||
["Tools"] = {
|
||||
name = "Tools",
|
||||
icon = "Interface\\Icons\\Trade_BlackSmithing",
|
||||
rules = {
|
||||
{ type = "isProfessionTool", value = true }
|
||||
},
|
||||
matchMode = "all",
|
||||
priority = 60,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
group = GROUP_OTHER,
|
||||
},
|
||||
["Empty"] = {
|
||||
name = "Empty",
|
||||
icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Bag",
|
||||
rules = {},
|
||||
matchMode = "all",
|
||||
priority = 0,
|
||||
priority = -10,
|
||||
enabled = true,
|
||||
isBuiltIn = true,
|
||||
hideControls = true,
|
||||
isEmptyCategory = true,
|
||||
group = GROUP_OTHER,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
-- Group definitions for display order and built-in group mapping
|
||||
local GROUP_ORDER = { GROUP_MAIN, GROUP_CLASS, GROUP_OTHER }
|
||||
|
||||
-- Map of built-in category IDs to their default groups (for migration)
|
||||
local BUILTIN_GROUP_MAP = {}
|
||||
for id, def in pairs(DEFAULT_CATEGORIES.definitions) do
|
||||
BUILTIN_GROUP_MAP[id] = def.group
|
||||
end
|
||||
|
||||
-- Deep copy a table
|
||||
local function deepCopy(orig)
|
||||
local copy
|
||||
@@ -404,6 +465,130 @@ function CategoryManager:MigrateCategories()
|
||||
addon:Debug("CategoryManager: Migrated Junk category to use isJunk rule")
|
||||
end
|
||||
end
|
||||
|
||||
-- Migrate: Add group to all categories that lack it
|
||||
for id, def in pairs(cats.definitions) do
|
||||
if not def.group then
|
||||
-- Use built-in mapping if available, otherwise default to Main
|
||||
def.group = BUILTIN_GROUP_MAP[id] or GROUP_MAIN
|
||||
addon:Debug("CategoryManager: Added group '%s' to category: %s", def.group, id)
|
||||
end
|
||||
end
|
||||
|
||||
-- Migrate: Convert per-category itemOverrides arrays to flat map at categories level
|
||||
if not cats.itemOverrides then
|
||||
cats.itemOverrides = {}
|
||||
end
|
||||
local migratedOverrides = false
|
||||
for catId, def in pairs(cats.definitions) do
|
||||
if def.itemOverrides and type(def.itemOverrides) == "table" then
|
||||
-- Check if it's an array (old format) by looking for numeric keys
|
||||
local isArray = false
|
||||
for k, v in pairs(def.itemOverrides) do
|
||||
if type(k) == "number" then
|
||||
isArray = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if isArray then
|
||||
for _, itemID in ipairs(def.itemOverrides) do
|
||||
cats.itemOverrides[itemID] = catId
|
||||
migratedOverrides = true
|
||||
end
|
||||
def.itemOverrides = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if migratedOverrides then
|
||||
addon:Debug("CategoryManager: Migrated per-category itemOverrides to flat map")
|
||||
end
|
||||
|
||||
-- Migrate Home category: add rules and remove hideControls
|
||||
local homeCat = cats.definitions["Home"]
|
||||
if homeCat and homeCat.isBuiltIn then
|
||||
-- Remove hideControls
|
||||
if homeCat.hideControls then
|
||||
homeCat.hideControls = nil
|
||||
addon:Debug("CategoryManager: Removed hideControls from Home")
|
||||
end
|
||||
-- Add rules if empty
|
||||
if not homeCat.rules or table.getn(homeCat.rules) == 0 then
|
||||
homeCat.rules = { { type = "itemID", value = {6948} } }
|
||||
homeCat.priority = 100
|
||||
addon:Debug("CategoryManager: Added itemID rule to Home category")
|
||||
end
|
||||
-- Ensure group is Other
|
||||
if homeCat.group ~= GROUP_OTHER then
|
||||
homeCat.group = GROUP_OTHER
|
||||
end
|
||||
end
|
||||
|
||||
-- Migrate Class Items: add isSoulShard rule if missing
|
||||
local classItemsCat = cats.definitions["Class Items"]
|
||||
if classItemsCat and classItemsCat.isBuiltIn then
|
||||
local hasSoulShard = false
|
||||
if classItemsCat.rules then
|
||||
for _, rule in ipairs(classItemsCat.rules) do
|
||||
if rule.type == "isSoulShard" then
|
||||
hasSoulShard = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not hasSoulShard then
|
||||
if not classItemsCat.rules then classItemsCat.rules = {} end
|
||||
table.insert(classItemsCat.rules, { type = "isSoulShard", value = true })
|
||||
classItemsCat.matchMode = "any"
|
||||
addon:Debug("CategoryManager: Added isSoulShard rule to Class Items")
|
||||
end
|
||||
end
|
||||
|
||||
-- Ensure new categories in the order list are in correct positions
|
||||
-- Check if order needs rebuilding to include new group-based ordering
|
||||
local hasTools, hasEmpty = false, false
|
||||
for _, id in ipairs(cats.order) do
|
||||
if id == "Tools" then hasTools = true end
|
||||
if id == "Empty" then hasEmpty = true end
|
||||
end
|
||||
|
||||
-- If Tools or Empty were just added by the built-in migration above,
|
||||
-- they're already at end of order. Move them to the Other group area.
|
||||
if hasTools or hasEmpty then
|
||||
-- Rebuild order to respect groups: Other, Main, Class
|
||||
local grouped = {}
|
||||
for _, g in ipairs(GROUP_ORDER) do
|
||||
grouped[g] = {}
|
||||
end
|
||||
grouped["_ungrouped"] = {}
|
||||
|
||||
for _, id in ipairs(cats.order) do
|
||||
local def = cats.definitions[id]
|
||||
if def then
|
||||
local g = def.group or GROUP_MAIN
|
||||
if grouped[g] then
|
||||
table.insert(grouped[g], id)
|
||||
else
|
||||
table.insert(grouped["_ungrouped"], id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Rebuild order
|
||||
local newOrder = {}
|
||||
for _, g in ipairs(GROUP_ORDER) do
|
||||
if grouped[g] then
|
||||
for _, id in ipairs(grouped[g]) do
|
||||
table.insert(newOrder, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
for _, id in ipairs(grouped["_ungrouped"]) do
|
||||
table.insert(newOrder, id)
|
||||
end
|
||||
|
||||
cats.order = newOrder
|
||||
addon:Debug("CategoryManager: Rebuilt category order for group ordering")
|
||||
end
|
||||
end
|
||||
|
||||
-- Get all categories
|
||||
@@ -438,20 +623,50 @@ function CategoryManager:SaveCategories(categories)
|
||||
end
|
||||
|
||||
-- Add a new custom category
|
||||
-- If categoryId is nil, auto-generates a unique ID like "Custom_<time>_<random>"
|
||||
function CategoryManager:AddCategory(categoryId, definition)
|
||||
local cats = self:GetCategories()
|
||||
|
||||
-- Auto-generate ID if not provided
|
||||
if not categoryId then
|
||||
categoryId = "Custom_" .. time() .. "_" .. math.random(1000, 9999)
|
||||
-- Ensure unique
|
||||
while cats.definitions[categoryId] do
|
||||
categoryId = "Custom_" .. time() .. "_" .. math.random(1000, 9999)
|
||||
end
|
||||
end
|
||||
|
||||
if cats.definitions[categoryId] then
|
||||
addon:Debug("CategoryManager: Category already exists: " .. categoryId)
|
||||
return false
|
||||
end
|
||||
|
||||
definition.isBuiltIn = false
|
||||
definition.isBuiltIn = definition.isBuiltIn or false
|
||||
if not definition.group then
|
||||
definition.group = GROUP_MAIN
|
||||
end
|
||||
cats.definitions[categoryId] = definition
|
||||
table.insert(cats.order, categoryId)
|
||||
|
||||
-- Insert at end of the category's group in the order list
|
||||
local insertPos = nil
|
||||
local group = definition.group
|
||||
-- Find last category in the same group
|
||||
for i = table.getn(cats.order), 1, -1 do
|
||||
local existDef = cats.definitions[cats.order[i]]
|
||||
if existDef and existDef.group == group then
|
||||
insertPos = i + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
if insertPos then
|
||||
-- Lua 5.0 table.insert with position
|
||||
table.insert(cats.order, insertPos, categoryId)
|
||||
else
|
||||
table.insert(cats.order, categoryId)
|
||||
end
|
||||
|
||||
self:SaveCategories(cats)
|
||||
return true
|
||||
return true, categoryId
|
||||
end
|
||||
|
||||
-- Update an existing category
|
||||
@@ -499,32 +714,106 @@ function CategoryManager:DeleteCategory(categoryId)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Move category up in order
|
||||
function CategoryManager:MoveCategoryUp(categoryId)
|
||||
-- Check if a category can move up within its group
|
||||
function CategoryManager:CanMoveUp(categoryId)
|
||||
local cats = self:GetCategories()
|
||||
local def = cats.definitions[categoryId]
|
||||
if not def or def.hideControls then return false end
|
||||
|
||||
for i, id in ipairs(cats.order) do
|
||||
if id == categoryId and i > 1 then
|
||||
cats.order[i] = cats.order[i - 1]
|
||||
cats.order[i - 1] = categoryId
|
||||
self:SaveCategories(cats)
|
||||
return true
|
||||
if id == categoryId then
|
||||
-- Find any previous non-hideControls category (can cross group boundaries)
|
||||
for j = i - 1, 1, -1 do
|
||||
local prevDef = cats.definitions[cats.order[j]]
|
||||
if prevDef and not prevDef.hideControls then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false -- very first movable category
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Move category down in order
|
||||
-- Check if a category can move down (crosses group boundaries)
|
||||
function CategoryManager:CanMoveDown(categoryId)
|
||||
local cats = self:GetCategories()
|
||||
local def = cats.definitions[categoryId]
|
||||
if not def or def.hideControls then return false end
|
||||
|
||||
local count = table.getn(cats.order)
|
||||
for i, id in ipairs(cats.order) do
|
||||
if id == categoryId then
|
||||
-- Find any next non-hideControls category (can cross group boundaries)
|
||||
for j = i + 1, count do
|
||||
local nextDef = cats.definitions[cats.order[j]]
|
||||
if nextDef and not nextDef.hideControls then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false -- very last movable category
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Move category up in order (crosses group boundaries, changes group when crossing)
|
||||
function CategoryManager:MoveCategoryUp(categoryId)
|
||||
local cats = self:GetCategories()
|
||||
local def = cats.definitions[categoryId]
|
||||
if not def or def.hideControls then return false end
|
||||
|
||||
for i, id in ipairs(cats.order) do
|
||||
if id == categoryId then
|
||||
-- Find previous non-hideControls category
|
||||
for j = i - 1, 1, -1 do
|
||||
local prevDef = cats.definitions[cats.order[j]]
|
||||
if prevDef and not prevDef.hideControls then
|
||||
-- Swap positions
|
||||
cats.order[i] = cats.order[j]
|
||||
cats.order[j] = categoryId
|
||||
-- If crossing into a different group, adopt that group
|
||||
local prevGroup = prevDef.group or GROUP_MAIN
|
||||
if (def.group or GROUP_MAIN) ~= prevGroup then
|
||||
def.group = prevGroup
|
||||
end
|
||||
self:SaveCategories(cats)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Move category down in order (crosses group boundaries, changes group when crossing)
|
||||
function CategoryManager:MoveCategoryDown(categoryId)
|
||||
local cats = self:GetCategories()
|
||||
local def = cats.definitions[categoryId]
|
||||
if not def or def.hideControls then return false end
|
||||
|
||||
local count = table.getn(cats.order)
|
||||
|
||||
for i, id in ipairs(cats.order) do
|
||||
if id == categoryId and i < count then
|
||||
cats.order[i] = cats.order[i + 1]
|
||||
cats.order[i + 1] = categoryId
|
||||
self:SaveCategories(cats)
|
||||
return true
|
||||
if id == categoryId then
|
||||
-- Find next non-hideControls category
|
||||
for j = i + 1, count do
|
||||
local nextDef = cats.definitions[cats.order[j]]
|
||||
if nextDef and not nextDef.hideControls then
|
||||
-- Swap positions
|
||||
cats.order[i] = cats.order[j]
|
||||
cats.order[j] = categoryId
|
||||
-- If crossing into a different group, adopt that group
|
||||
local nextGroup = nextDef.group or GROUP_MAIN
|
||||
if (def.group or GROUP_MAIN) ~= nextGroup then
|
||||
def.group = nextGroup
|
||||
end
|
||||
self:SaveCategories(cats)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
return false
|
||||
@@ -742,6 +1031,26 @@ function CategoryManager:CategorizeItem(itemData, bagID, slotID, isOtherChar)
|
||||
end
|
||||
cacheMisses = cacheMisses + 1
|
||||
|
||||
-- Check item overrides first (flat map: itemID -> categoryId)
|
||||
if itemData and itemData.link then
|
||||
local itemID = addon.Modules.Utils:ExtractItemID(itemData.link)
|
||||
if itemID then
|
||||
local cats = self:GetCategories()
|
||||
if cats.itemOverrides then
|
||||
local overrideCatId = cats.itemOverrides[itemID]
|
||||
if overrideCatId then
|
||||
local overrideDef = cats.definitions[overrideCatId]
|
||||
if overrideDef and overrideDef.enabled then
|
||||
if cacheKey then
|
||||
categoryCache[cacheKey] = overrideCatId
|
||||
end
|
||||
return overrideCatId
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local sortedCats = self:GetCategoriesByPriority()
|
||||
|
||||
-- Debug: show white item categorization
|
||||
@@ -791,6 +1100,243 @@ function CategoryManager:BuildCategoryList()
|
||||
return list
|
||||
end
|
||||
|
||||
-------------------------------------------
|
||||
-- Group Management
|
||||
-------------------------------------------
|
||||
|
||||
-- Get ordered list of unique groups from the category order
|
||||
function CategoryManager:GetGroups()
|
||||
local cats = self:GetCategories()
|
||||
local seen = {}
|
||||
local groups = {}
|
||||
for _, id in ipairs(cats.order) do
|
||||
local def = cats.definitions[id]
|
||||
if def then
|
||||
local g = def.group or GROUP_MAIN
|
||||
if not seen[g] then
|
||||
seen[g] = true
|
||||
table.insert(groups, g)
|
||||
end
|
||||
end
|
||||
end
|
||||
return groups
|
||||
end
|
||||
|
||||
-- Get categories organized by group: { groupName => {catIds} }
|
||||
-- Also returns ungrouped list for any categories without a group
|
||||
function CategoryManager:GetCategoriesByGroup()
|
||||
local cats = self:GetCategories()
|
||||
local result = {}
|
||||
local ungrouped = {}
|
||||
|
||||
for _, id in ipairs(cats.order) do
|
||||
local def = cats.definitions[id]
|
||||
if def then
|
||||
local g = def.group
|
||||
if g then
|
||||
if not result[g] then result[g] = {} end
|
||||
table.insert(result[g], id)
|
||||
else
|
||||
table.insert(ungrouped, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result, ungrouped
|
||||
end
|
||||
|
||||
-- Change a category's group
|
||||
function CategoryManager:SetCategoryGroup(categoryId, groupName)
|
||||
local cats = self:GetCategories()
|
||||
local def = cats.definitions[categoryId]
|
||||
if not def then return false end
|
||||
|
||||
local oldGroup = def.group or GROUP_MAIN
|
||||
if oldGroup == groupName then return true end
|
||||
|
||||
def.group = groupName
|
||||
|
||||
-- Remove from current position in order
|
||||
local currentPos = nil
|
||||
for i, id in ipairs(cats.order) do
|
||||
if id == categoryId then
|
||||
currentPos = i
|
||||
break
|
||||
end
|
||||
end
|
||||
if currentPos then
|
||||
table.remove(cats.order, currentPos)
|
||||
end
|
||||
|
||||
-- Insert at end of new group
|
||||
local insertPos = nil
|
||||
for i = table.getn(cats.order), 1, -1 do
|
||||
local existDef = cats.definitions[cats.order[i]]
|
||||
if existDef and (existDef.group or GROUP_MAIN) == groupName then
|
||||
insertPos = i + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
if insertPos then
|
||||
table.insert(cats.order, insertPos, categoryId)
|
||||
else
|
||||
table.insert(cats.order, categoryId)
|
||||
end
|
||||
|
||||
self:SaveCategories(cats)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Get the group order (unique groups in display order)
|
||||
function CategoryManager:GetGroupOrder()
|
||||
return self:GetGroups()
|
||||
end
|
||||
|
||||
|
||||
-- Get group constants
|
||||
function CategoryManager:GetGroupMain() return GROUP_MAIN end
|
||||
function CategoryManager:GetGroupOther() return GROUP_OTHER end
|
||||
function CategoryManager:GetGroupClass() return GROUP_CLASS end
|
||||
|
||||
-------------------------------------------
|
||||
-- Item Override System
|
||||
-------------------------------------------
|
||||
|
||||
-- Assign an item to a specific category by item ID
|
||||
-- Uses flat map at categories level: cats.itemOverrides[itemID] = categoryId
|
||||
function CategoryManager:AssignItemToCategory(itemID, categoryId)
|
||||
if not itemID or not categoryId then return false end
|
||||
local cats = self:GetCategories()
|
||||
local def = cats.definitions[categoryId]
|
||||
if not def then return false end
|
||||
|
||||
if not cats.itemOverrides then
|
||||
cats.itemOverrides = {}
|
||||
end
|
||||
|
||||
cats.itemOverrides[itemID] = categoryId
|
||||
self:SaveCategories(cats)
|
||||
self:ClearCache()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Remove an item from a specific category's overrides
|
||||
function CategoryManager:RemoveItemFromCategory(itemID, categoryId)
|
||||
if not itemID or not categoryId then return false end
|
||||
local cats = self:GetCategories()
|
||||
if not cats.itemOverrides then return false end
|
||||
|
||||
if cats.itemOverrides[itemID] == categoryId then
|
||||
cats.itemOverrides[itemID] = nil
|
||||
self:SaveCategories(cats)
|
||||
self:ClearCache()
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Remove an item override regardless of category
|
||||
function CategoryManager:RemoveItemOverride(itemID)
|
||||
if not itemID then return end
|
||||
local cats = self:GetCategories()
|
||||
if cats.itemOverrides then
|
||||
cats.itemOverrides[itemID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------
|
||||
-- Equipment Set Category Sync
|
||||
-------------------------------------------
|
||||
|
||||
-- Saved properties for equipment set categories that were user-edited
|
||||
-- Preserves user changes (enabled state, order position) when sets are deleted/recreated
|
||||
local savedEquipSetProps = {}
|
||||
|
||||
-- Sync equipment set categories with current set data from EquipmentSets module
|
||||
function CategoryManager:SyncEquipmentSetCategories()
|
||||
local equipSets = addon.Modules.EquipmentSets
|
||||
if not equipSets then return end
|
||||
|
||||
local showEquipSets = addon.Modules.DB:GetSetting("showEquipSetCategories")
|
||||
if showEquipSets == false then return end
|
||||
|
||||
local setNames = equipSets:GetAllSetNames()
|
||||
if not setNames then return end
|
||||
|
||||
local cats = self:GetCategories()
|
||||
local existingSetCats = {}
|
||||
|
||||
-- Find existing EquipSet categories
|
||||
for id, def in pairs(cats.definitions) do
|
||||
if string.find(id, "^EquipSet:") then
|
||||
existingSetCats[id] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Create/update categories for current sets
|
||||
for _, setName in ipairs(setNames) do
|
||||
local catId = "EquipSet:" .. setName
|
||||
if not cats.definitions[catId] then
|
||||
-- Check for saved properties from a previously deleted set
|
||||
local props = savedEquipSetProps[catId]
|
||||
local defaultMark = "Interface\\AddOns\\Guda\\Assets\\equipment"
|
||||
local newDef = {
|
||||
name = setName,
|
||||
icon = "Interface\\Icons\\INV_Chest_Chain_04",
|
||||
rules = {},
|
||||
matchMode = "all",
|
||||
priority = 65,
|
||||
enabled = props and props.enabled or true,
|
||||
isBuiltIn = false,
|
||||
isEquipSetCategory = true,
|
||||
group = GROUP_MAIN,
|
||||
categoryMark = props and props.categoryMark or defaultMark,
|
||||
}
|
||||
cats.definitions[catId] = newDef
|
||||
|
||||
-- Add to order
|
||||
local insertPos = nil
|
||||
for i = table.getn(cats.order), 1, -1 do
|
||||
local existDef = cats.definitions[cats.order[i]]
|
||||
if existDef and (existDef.group or GROUP_MAIN) == GROUP_MAIN then
|
||||
insertPos = i + 1
|
||||
break
|
||||
end
|
||||
end
|
||||
if insertPos then
|
||||
table.insert(cats.order, insertPos, catId)
|
||||
else
|
||||
table.insert(cats.order, catId)
|
||||
end
|
||||
|
||||
addon:Debug("CategoryManager: Created equipment set category: " .. catId)
|
||||
end
|
||||
existingSetCats[catId] = nil -- Mark as still active
|
||||
end
|
||||
|
||||
-- Remove categories for sets that no longer exist
|
||||
for catId in pairs(existingSetCats) do
|
||||
local def = cats.definitions[catId]
|
||||
if def then
|
||||
-- Save user-edited properties before deletion
|
||||
savedEquipSetProps[catId] = {
|
||||
enabled = def.enabled,
|
||||
categoryMark = def.categoryMark,
|
||||
}
|
||||
end
|
||||
cats.definitions[catId] = nil
|
||||
for i, id in ipairs(cats.order) do
|
||||
if id == catId then
|
||||
table.remove(cats.order, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
addon:Debug("CategoryManager: Removed equipment set category: " .. catId)
|
||||
end
|
||||
|
||||
self:SaveCategories(cats)
|
||||
end
|
||||
|
||||
-- Get available rule types for UI
|
||||
function CategoryManager:GetRuleTypes()
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user