-- read namespace from global env local _G = _G local Grichelde = _G.Grichelde local nilOrEmpty, pairs, find, match, toString, toNumber = Grichelde.functions.nilOrEmpty, Grichelde.functions.pairs, Grichelde.functions.find, Grichelde.functions.match, Grichelde.functions.toString, Grichelde.functions.toNumber function Grichelde:CreateOptionsUI() return { name = self:Format(self.L.Options_Title, self.L.AddonName), type = "group", childGroups = "tab", set = function(info, val) self:SyncToDatabase(info, val) end, get = function(info) return self:ReadFromDatabase(info) end, hidden = false, disabled = function(info) return self:IsDisabled(info) end, args = { enabled = { order = 0, type = "toggle", name = self.L.Options_Enabled_Name, desc = self:Format(self.L.Options_Enabled_Desc, self.L.AddonName), disabled = false, }, channels = { order = 2, type = "group", name = self.L.Options_Channels_Group_Name, desc = self:Format(self.L.Options_Channels_Group_Desc, self.L.AddonName), args = { header = { order = 1, type = "description", name = self.L.Options_Channels_Header }, spacer = { order = 2, type = "header", name = "" }, say = { order = 10, type = "toggle", name = self.L.Options_Channel_Say_Name, desc = self:Format(self.L.Options_Channel_Say_Desc, self.L.AddonName), }, emote = { order = 11, type = "toggle", name = self.L.Options_Channel_Emote_Name, desc = self:Format(self.L.Options_Channel_Emote_Desc, self.L.AddonName), }, yell = { order = 12, type = "toggle", name = self.L.Options_Channel_Yell_Name, desc = self:Format(self.L.Options_Channel_Yell_Desc, self.L.AddonName), }, party = { order = 13, type = "toggle", name = self.L.Options_Channel_Party_Name, desc = self:Format(self.L.Options_Channel_Party_Desc, self.L.AddonName), }, guild = { order = 14, type = "toggle", name = self.L.Options_Channel_Guild_Name, desc = self:Format(self.L.Options_Channel_Guild_Desc, self.L.AddonName), }, officer = { order = 15, type = "toggle", name = self.L.Options_Channel_Officer_Name, desc = self:Format(self.L.Options_Channel_Officer_Desc, self.L.AddonName), }, raid = { order = 16, type = "toggle", name = self.L.Options_Channel_Raid_Name, desc = self:Format(self.L.Options_Channel_Raid_Desc, self.L.AddonName), }, raidWarning = { order = 17, type = "toggle", name = self.L.Options_Channel_RaidWarning_Name, desc = self:Format(self.L.Options_Channel_RaidWarning_Desc, self.L.AddonName), }, instance = { order = 18, type = "toggle", name = self.L.Options_Channel_Instance_Name, desc = self:Format(self.L.Options_Channel_Instance_Desc, self.L.AddonName), }, battleground = { order = 19, type = "toggle", name = self.L.Options_Channel_Battleground_Name, desc = self:Format(self.L.Options_Channel_Battleground_Desc, self.L.AddonName), }, whisper = { order = 20, type = "toggle", name = self.L.Options_Channel_Whisper_Name, desc = self:Format(self.L.Options_Channel_Whisper_Desc, self.L.AddonName), }, } }, replacements = { order = 3, type = "group", name = self.L.Options_Replacements_Group_Name, desc = self.L.Options_Replacements_Group_Desc, args = { add = { order = 0, type = "execute", confirm = false, name = self.L.Options_Replacements_Add_Name, desc = self.L.Options_Replacements_Add_Desc, func = function(info) self:AddEmptyMapping(info) end }, deleteAll = { order = 1, type = "execute", confirm = true, confirmText = self.L.Options_Replacements_DeleteAll_ConfirmText, name = self.L.Options_Replacements_DeleteAll_Name, desc = self.L.Options_Replacements_DeleteAll_Desc, func = function(info) self:DeleteAllMappings(info) end }, header = { order = 3, type = "description", name = self.L.Options_Replacements_Header }, spacer = { order = 4, type = "header", name = "" }, } } } } end function Grichelde:CreateMapping(offset) return { order = offset or 9999, type = "group", name = function(info) return self:MappingName(info) end, desc = self.L.Options_Mapping_Group_Desc, childGroups = "tree", args = { searchText = { order = 0, type = "input", name = self.L.Options_Mapping_SearchText_Name, desc = self.L.Options_Mapping_SearchText_Desc, }, replaceText = { order = 1, type = "input", name = self.L.Options_Mapping_ReplaceText_Name, desc = self.L.Options_Mapping_ReplaceText_Desc, }, exactCase = { order = 2, type = "toggle", name = self.L.Options_Mapping_ExactCase_Name, desc = self.L.Options_Mapping_ExactCase_Desc, width = "full", }, consolidate = { order = 3, type = "toggle", name = self.L.Options_Mapping_Consolidate_Name, desc = self.L.Options_Mapping_Consolidate_Desc, width = "full" }, moveUp = { order = 10, type = "execute", name = self.L.Options_Mapping_MoveUp_Name, desc = self.L.Options_Mapping_MoveUp_Desc, width = 0.25, func = function(info) self:MoveUp(info) end }, moveDown = { order = 11, type = "execute", name = self.L.Options_Mapping_MoveDown_Name, desc = self.L.Options_Mapping_MoveDown_Desc, width = 0.25, func = function(info) self:MoveDown(info) end }, spacer = { order = 18, type = "description", name = "", width = 1, }, delete = { order = 19, type = "execute", confirm = true, confirmText = self.L.Options_Mapping_Delete_ConfirmText, name = self.L.Options_Mapping_Delete_Name, desc = self.L.Options_Mapping_Delete_Desc, width = 0.5, func = function(info) self:DeleteMapping(info) end }, } } end function Grichelde:SetupOptions() -- add DB-backed profiles to UI options local options = self:CreateOptionsUI() options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) options.args.profiles.disabled = false -- Adding options to blizzard frame LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, options) local dialog = LibStub("AceConfigDialog-3.0") dialog:AddToBlizOptions(self.name, self.L.AddonName) return options, dialog end function Grichelde:IsDisabled(info) if info.option.type == "group" then return false end return not self.db.profile.enabled end function Grichelde:MappingName(info) -- self:TracePrint("MappingName : info") -- self:TracePrint(info) local option = self.db.profile.replacements[info[2]] if nilOrEmpty(option.searchText) and nilOrEmpty(option.replaceText) then return self.L.Options_Mapping_EmptyMapping else return self:Format(self.L.Options_Mapping_Group_Name, option.searchText or "", option.replaceText or "") end end function Grichelde:RefreshOptions(event) self:DebugPrint("RefreshOptions : event:", event) if event == "OnNewProfile" then self:PrefixedPrint(self.L.Profiles_Created, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) elseif event == "OnProfileChanged" then self:PrefixedPrint(self.L.Profiles_Loaded, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) elseif event == "OnProfileDeleted" then self:PrefixedPrint(self.L.Profiles_Deleted, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) elseif event == "OnProfileCopied" then self:PrefixedPrint(self.L.Profiles_Copied, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) elseif event == "OnProfileReset" then self:PrefixedPrint(self.L.Profiles_Reset, self.COLOR_CODES.GREEN .. self.db:GetCurrentProfile() .. self.COLOR_CODES.CLOSE) else self:DebugPrint("Refreshing Profile %s on options change: %s", self.db:GetCurrentProfile(), event) end self:ReorderReplacements() self:RefreshReplacements(self.db.profile.replacements) end --- Create UI options for rhe given replacement table (from DB). --- Usually called with with self.db.profile.replacements -- @param replacementsTable function Grichelde:RefreshReplacements(replacementsTable) self:TracePrint("RefreshReplacements : DB table:") self:TracePrint(replacementsTable) -- remove all previous replacements from options (not DB), except header and buttons local replacements = self.options.args.replacements.args or {} for k, _ in pairs(replacements) do if k and find(k, "^replacement_") then replacements[k] = nil end end for replName, _ in pairs(replacementsTable or {}) do local _, replNumber = self:SplitOnFirstMatch(replName, "_") replacements[replName] = self:CreateMapping(toNumber(replNumber)) end -- self:TracePrint("RefreshReplacements : UI options:") -- self:TracePrint(replacements) self.dialog:ConfigTableChanged(nil, self.name) end function Grichelde:AddEmptyMapping() local replacements = self.db.profile.replacements or {} self:DebugPrint("AddEmptyMapping : old DB entries:") self:DebugPrint(replacements) local maxRepl = Grichelde.MAPPING_OFFSET for replName, _ in pairs(replacements) do local num = match(replName, "^replacement_(%d+)") if num and maxRepl < toNumber(num) then maxRepl = toNumber(num) end end local newMapping = "replacement_" .. toString(maxRepl + 1) self:DebugPrint("AddEmptyMapping : new mapping key:", newMapping) -- do NOT set self.db.profile.replacements = {} it will break defaults replacements[newMapping].order = toString(maxRepl + 1) -- will be reordered anyway self:DebugPrint("AddEmptyMapping : new DB entries:") self:DebugPrint(replacements) self:RefreshOptions("AddEmptyMapping " .. newMapping) self.dialog:SelectGroup(self.name, "replacements", newMapping) end function Grichelde:MoveUp(info) self:TracePrint("MoveUp : info") for i = 0, #info do self:TracePrint("%d = %s", i, info[i]) end local replacements = self.db.profile.replacements or {} local currentName = info[2] self:DebugPrint("MoveUp : \"%s\"", currentName) self:DebugPrint(replacements[currentName]) local _, replNumber = self:SplitOnFirstMatch(currentName, "_") local currentOrder = toNumber(replNumber) -- if not on top if currentOrder ~= Grichelde.MAPPING_OFFSET then local swapName = "replacement_" .. toString(currentOrder - 1) -- swap ordering self:DebugPrint("swap with option %s", swapName) replacements[swapName].order = currentOrder replacements[currentName].order = currentOrder - 1 self:RefreshOptions("MoveUp " .. currentName) self:DebugPrint("MoveUp : refresh focus on %s", swapName) self.dialog:SelectGroup(self.name, "replacements", swapName) else self:DebugPrint("MoveUp : already on top") end end function Grichelde:MoveDown(info) self:TracePrint("MoveDown : info") for i = 0, #info do self:TracePrint("%d = %s", i, info[i]) end local replacements = self.db.profile.replacements or {} local currentName = info[2] self:DebugPrint("MoveDown : \"%s\"", currentName) self:DebugPrint(replacements[currentName]) local _, replNumber = self:SplitOnFirstMatch(currentName, "_") local currentOrder = toNumber(replNumber) local maxRepl = Grichelde.MAPPING_OFFSET for replName, _ in pairs(replacements) do local num = match(replName, "^replacement_(%d+)") if num and maxRepl < toNumber(num) then maxRepl = toNumber(num) end end -- if not last element self:DebugPrint("MoveDown : maxRepl: %d", maxRepl) if currentOrder < maxRepl then local swapName = "replacement_" .. toString(currentOrder + 1) -- swap ordering self:DebugPrint("swap with option %s", swapName) replacements[swapName].order = currentOrder replacements[currentName].order = currentOrder + 1 self:RefreshOptions("MoveDown " .. currentName) self:DebugPrint("MoveDown : refresh focus on %s", swapName) self.dialog:SelectGroup(self.name, "replacements", swapName) else self:DebugPrint("MoveDown : already at bottom") end end function Grichelde:DeleteMapping(info) self:TracePrint("DeleteMapping : info") for i = 0, #info do self:TracePrint("%d = %s", i, info[i]) end local currentName = info[2] self:DebugPrint("delete option: %s", currentName) self.db.profile.replacements[currentName] = nil self:RefreshOptions("DeleteMapping " .. currentName) local _, replNumber = self:SplitOnFirstMatch(currentName, "_") local newMapping = "replacement_" .. toNumber(replNumber - 1) self.dialog:SelectGroup(self.name, "replacements", newMapping) end function Grichelde:DeleteAllMappings() self:DebugPrint("DeleteAllMappings") -- do NOT set self.db.profile.replacements = {} it will break defaults for replName, _ in pairs(self.db.profile.replacements or {}) do self.db.profile.replacements[replName] = nil end self:AddEmptyMapping() self:RefreshOptions("DeleteAllMappings") end