local E, L, V, P, G = unpack(ElvUI) local EP = E.Libs.EP local ACH = LibStub("LibAceConfigHelper") local AceDB = LibStub("AceDB-3.0") local AceDBOptions = LibStub("AceDBOptions-3.0") local AddOnName = ... BINDING_HEADER_COA = "Conquest of Azeroth" -- TODO: hook up server restart frame (RestartTimerFrame) local CoA = E:NewModule("CoA", "AceEvent-3.0", "AceTimer-3.0") E.CoA = CoA local defaults = { profile = { skins = { extraActionButton = true, instanceSwap = true, collections = { enable = true, -- Multipliers on each frame's own scale, so 1 is "as the server -- built it" rather than a fixed size. advancementScale = 1, vanityScale = 1, wardrobeScale = 1, }, interfaceOptions = true, }, extraActionButtonSize = 52, instanceButtonFont = "PT Sans Narrow", instanceButtonFontSize = 12, instanceButtonFontOutline = "OUTLINE", dispelHighlightOnlyMine = false, dispelHighlightDetectTalents = true, hideResourceSegmentBar = false, hideResourceOrb = false, hideResourceBar = false, hideMultiCastActionBar = false, }, } function CoA:RefreshConfig() if self.UpdateExtraActionButtonSize then self:UpdateExtraActionButtonSize() end if self.UpdateInstanceButtonFont then self:UpdateInstanceButtonFont() end if self.UpdateDispelHighlight then self:UpdateDispelHighlight() end if self.UpdateClassResourceVisibility then self:UpdateClassResourceVisibility() end if self.UpdateFrameScales then self:UpdateFrameScales() end end CoA:RegisterEvent("ADDON_LOADED", function(_, addon) if addon ~= AddOnName then return end CoA:UnregisterEvent("ADDON_LOADED") CoA.db = AceDB:New("ElvUI_CoADB", defaults) -- One-time migration: earlier versions pinned every character to a single -- shared "Default" profile. Move each character to its own name-based -- profile (copying over the settings it already had) the first time it logs in. if not CoA.db.char.migratedSharedProfile then local charProfile = CoA.db.keys.char if CoA.db:GetCurrentProfile() == "Default" and charProfile ~= "Default" then CoA.db:SetProfile(charProfile) CoA.db:CopyProfile("Default", true) end CoA.db.char.migratedSharedProfile = true end CoA.db.RegisterCallback(CoA, "OnProfileChanged", "RefreshConfig") CoA.db.RegisterCallback(CoA, "OnProfileCopied", "RefreshConfig") CoA.db.RegisterCallback(CoA, "OnProfileReset", "RefreshConfig") end) -- One slider per window rather than a single shared one: the three don't ship -- at the same scale, so a shared value would only line them up by flattening -- the difference the server built in. local function scaleOption(order, name, key) return { order = order, type = "range", name = name, min = 0.5, max = 1.5, step = 0.01, get = function() return CoA.db.profile.skins.collections[key] end, set = function(_, value) CoA.db.profile.skins.collections[key] = value if CoA.UpdateFrameScales then CoA:UpdateFrameScales() end end, } end local function getOptions() local profiles = AceDBOptions:GetOptionsTable(CoA.db) profiles.order = 5 local options = { order = 55, type = "group", childGroups = "tab", name = string.format("|cff1784d1%s|r", "Conquest of Azeroth"), args = { -- Frame skins live under their own tab, laid out as a vertical tree -- rather than more horizontal tabs: one entry per skinned frame, and -- there are a lot more of those coming. skins = { order = 1, type = "group", childGroups = "tree", name = "Skins", args = { extraActionButton = { order = 1, type = "group", name = "Extra Action Button", args = { header = { order = 1, type = "header", name = "Extra Action Button", }, -- Skinning is one-way: the native art is stripped and -- replaced in place, so turning a skin off can only take -- effect on the next load. Hence the reload prompt. enable = { order = 2, type = "toggle", name = "Enable", desc = "Skin the Extra Action Button. Requires a UI reload.", get = function() return CoA.db.profile.skins.extraActionButton end, set = function(_, value) CoA.db.profile.skins.extraActionButton = value E:StaticPopup_Show("CONFIG_RL") end, }, desc = { order = 3, type = "description", name = "You can move this element with Toggle Anchors.\n", }, size = { order = 4, disabled = function() return not CoA.db.profile.skins.extraActionButton end, type = "range", name = "Size", desc = "Adjust the width/height of the Extra Action Button, in pixels.", min = 30, max = 100, step = 1, get = function() return CoA.db.profile.extraActionButtonSize end, set = function(_, value) CoA.db.profile.extraActionButtonSize = value if CoA.UpdateExtraActionButtonSize then CoA:UpdateExtraActionButtonSize() end end, }, }, }, instanceSwap = { order = 2, type = "group", name = "Instance Swap", args = { header = { order = 1, type = "header", name = "Instance Swap", }, enable = { order = 2, type = "toggle", name = "Enable", desc = "Skin the Instance Swap button. Requires a UI reload.", get = function() return CoA.db.profile.skins.instanceSwap end, set = function(_, value) CoA.db.profile.skins.instanceSwap = value E:StaticPopup_Show("CONFIG_RL") end, }, desc = { order = 3, type = "description", name = "You can move this element with Toggle Anchors.\n", }, instanceFont = { order = 4, disabled = function() return not CoA.db.profile.skins.instanceSwap end, type = "group", inline = true, name = "Instance Font", args = { font = ACH:SharedMediaFont("Font", nil, 1, nil, function() return CoA.db.profile.instanceButtonFont end, function(_, value) CoA.db.profile.instanceButtonFont = value if CoA.UpdateInstanceButtonFont then CoA:UpdateInstanceButtonFont() end end), fontSize = { order = 2, type = "range", name = "Font Size", min = 8, max = 32, step = 1, get = function() return CoA.db.profile.instanceButtonFontSize end, set = function(_, value) CoA.db.profile.instanceButtonFontSize = value if CoA.UpdateInstanceButtonFont then CoA:UpdateInstanceButtonFont() end end, }, fontOutline = ACH:FontFlags("Font Outline", nil, 3, nil, function() return CoA.db.profile.instanceButtonFontOutline end, function(_, value) CoA.db.profile.instanceButtonFontOutline = value if CoA.UpdateInstanceButtonFont then CoA:UpdateInstanceButtonFont() end end), }, }, }, }, -- One entry for the whole talent window: its own frame, the -- tab row along its bottom, and the Vanity and Wardrobe -- windows those tabs open. They're separate frames but one -- feature to the player, and they're skinned as a set -- -- named for Collections, the container they all hang off. collections = { order = 3, type = "group", name = "Advancement/Vanity/Wardrobe", args = { header = { order = 1, type = "header", name = "Advancement/Vanity/Wardrobe", }, enable = { order = 2, type = "toggle", name = "Enable", desc = "Skin the talent window, its tabs, and the Vanity and Wardrobe windows. Requires a UI reload.", get = function() return CoA.db.profile.skins.collections.enable end, set = function(_, value) CoA.db.profile.skins.collections.enable = value E:StaticPopup_Show("CONFIG_RL") end, }, scale = { order = 3, type = "group", inline = true, name = "Scale", disabled = function() return not CoA.db.profile.skins.collections.enable end, args = { advancementScale = scaleOption(1, "Advancement", "advancementScale"), vanityScale = scaleOption(2, "Vanity", "vanityScale"), wardrobeScale = scaleOption(3, "Wardrobe", "wardrobeScale"), }, }, }, }, interfaceOptions = { order = 5, type = "group", name = "Interface Options", args = { header = { order = 1, type = "header", name = "Interface Options", }, enable = { order = 2, type = "toggle", name = "Enable", desc = "Skin the options the CoA client adds to the stock Interface, Video and Audio windows, which ElvUI's own pass doesn't cover. Requires a UI reload.", get = function() return CoA.db.profile.skins.interfaceOptions end, set = function(_, value) CoA.db.profile.skins.interfaceOptions = value E:StaticPopup_Show("CONFIG_RL") end, }, }, }, }, }, classResources = { order = 2, type = "group", name = "Class Resources", args = { header = { order = 1, type = "header", name = "Class Resources", }, desc = { order = 2, type = "description", name = "You can move these elements with Toggle Anchors.\n", }, hideResourceSegmentBar = { order = 3, type = "toggle", name = "Hide CoAResourceSegmentBar", width = "full", get = function() return CoA.db.profile.hideResourceSegmentBar end, set = function(_, value) CoA.db.profile.hideResourceSegmentBar = value if CoA.UpdateClassResourceVisibility then CoA:UpdateClassResourceVisibility() end end, }, hideResourceOrb = { order = 4, type = "toggle", name = "Hide CoAResourceOrb", width = "full", get = function() return CoA.db.profile.hideResourceOrb end, set = function(_, value) CoA.db.profile.hideResourceOrb = value if CoA.UpdateClassResourceVisibility then CoA:UpdateClassResourceVisibility() end end, }, hideResourceBar = { order = 5, type = "toggle", name = "Hide CoAResourceBar", width = "full", get = function() return CoA.db.profile.hideResourceBar end, set = function(_, value) CoA.db.profile.hideResourceBar = value if CoA.UpdateClassResourceVisibility then CoA:UpdateClassResourceVisibility() end end, }, hideMultiCastActionBar = { order = 6, type = "toggle", name = "Hide CoAMultiCastActionBarFrame", width = "full", get = function() return CoA.db.profile.hideMultiCastActionBar end, set = function(_, value) CoA.db.profile.hideMultiCastActionBar = value if CoA.UpdateClassResourceVisibility then CoA:UpdateClassResourceVisibility() end end, }, hideAll = { order = 7, type = "execute", name = "Hide All", func = function() CoA.db.profile.hideResourceSegmentBar = true CoA.db.profile.hideResourceOrb = true CoA.db.profile.hideResourceBar = true CoA.db.profile.hideMultiCastActionBar = true if CoA.UpdateClassResourceVisibility then CoA:UpdateClassResourceVisibility() end end, }, showAll = { order = 8, type = "execute", name = "Show All", func = function() CoA.db.profile.hideResourceSegmentBar = false CoA.db.profile.hideResourceOrb = false CoA.db.profile.hideResourceBar = false CoA.db.profile.hideMultiCastActionBar = false if CoA.UpdateClassResourceVisibility then CoA:UpdateClassResourceVisibility() end end, }, }, }, dispelHighlight = { order = 3, type = "group", name = "Debuff Highlighting", args = { header = { order = 1, type = "header", name = "Debuff Highlighting", }, onlyMine = { order = 2, type = "toggle", name = "Only Highlight If Dispellable By Me", desc = "Suppress the debuff highlight on unitframes for debuff types your class cannot dispel.", get = function() return CoA.db.profile.dispelHighlightOnlyMine end, set = function(_, value) CoA.db.profile.dispelHighlightOnlyMine = value if CoA.UpdateDispelHighlight then CoA:UpdateDispelHighlight() end end, }, detectTalents = { order = 3, type = "toggle", name = "Detect Talents", desc = "Read the talents that grant extra dispel types from your current build. Turn this off to fall back to what your class can dispel without any talent.", disabled = function() return not CoA.db.profile.dispelHighlightOnlyMine end, get = function() return CoA.db.profile.dispelHighlightDetectTalents end, set = function(_, value) CoA.db.profile.dispelHighlightDetectTalents = value if CoA.UpdateDispelHighlight then CoA:UpdateDispelHighlight() end end, }, }, }, profiles = profiles, }, } E.Options.args.CoA = options end local function RegisterMoverCategory() for _, layout in ipairs(E.ConfigModeLayouts) do if layout == "COA" then return end end tinsert(E.ConfigModeLayouts, "COA") E.ConfigModeLocalizedStrings.COA = "CoA" end function CoA:Initialize() RegisterMoverCategory() EP:RegisterPlugin(AddOnName, getOptions) -- ADDON_LOADED normally beats module init, but fall back to the defaults -- rather than error out if a skin gets initialized before the DB exists. local skins = self.db and self.db.profile.skins or defaults.profile.skins if self.InitializeExtraActionBar and skins.extraActionButton then self:InitializeExtraActionBar() end if self.InitializeLayerPicker and skins.instanceSwap then self:InitializeLayerPicker() end if self.InitializeDispelHighlight then self:InitializeDispelHighlight() end if self.InitializeClassResources then self:InitializeClassResources() end -- One switch for all three: the vanity and wardrobe windows are the talent -- frame's own tabs, so skinning one without the others reads as a bug. if skins.collections.enable then if self.InitializeTalentFrame then self:InitializeTalentFrame() end if self.InitializeVanityFrame then self:InitializeVanityFrame() end if self.InitializeWardrobeFrame then self:InitializeWardrobeFrame() end end if self.InitializeInterfaceOptions and skins.interfaceOptions then self:InitializeInterfaceOptions() end end local function InitializeCallback() CoA:Initialize() end E:RegisterModule(CoA:GetName(), InitializeCallback)