local BigWigs = BigWigs local options = {} local C = BigWigs.C local L = BigWigsAPI:GetLocale("BigWigs") local ldbi = LibStub("LibDBIcon-1.0") local acr = LibStub("AceConfigRegistry-3.0") local acd = LibStub("AceConfigDialog-3.0") local AceGUI = LibStub("AceGUI-3.0") local adbo = LibStub("AceDBOptions-3.0") local lds = LibStub("LibDualSpec-1.0") local loader = BigWigsLoader local API = BigWigsAPI options.SendMessage = loader.SendMessage local UnitName = loader.UnitName local bwTooltip = CreateFrame("GameTooltip", "BigWigsOptionsTooltip", UIParent, "GameTooltipTemplate") local colorModule local soundModule local configFrame, isPluginOpen local showToggleOptions, getAdvancedToggleOption = nil, nil local getOptions local acOptions = { type = "group", name = "BigWigs", get = function(info) return BigWigs.db.profile[info[#info]] end, set = function(info, value) local key = info[#info] BigWigs.db.profile[key] = value options:SendMessage("BigWigs_CoreOptionToggled", key, value) end, args = { general = { order = 20, type = "group", name = "BigWigs", args = { introduction = { type = "description", name = L.introduction, order = 12, fontSize = "medium", width = "full", }, anchorsButton = { type = "execute", name = function() if options:InConfigureMode() then return L.toggleAnchorsBtnHide else return L.toggleAnchorsBtnShow end end, desc = function() if options:InConfigureMode() then return L.toggleAnchorsBtnHide_desc else return L.toggleAnchorsBtnShow_desc end end, func = function() if not BigWigs:IsEnabled() then BigWigs:Enable() end if options:InConfigureMode() then options:SendMessage("BigWigs_StopConfigureMode") else options:SendMessage("BigWigs_StartConfigureMode") end end, width = 1.5, order = 12.4, }, testButton = { type = "execute", name = L.testBarsBtn, desc = L.testBarsBtn_desc, func = function() BigWigs:Test() end, width = 1.5, order = 12.5, }, minimap = { type = "toggle", name = L.minimapIcon, desc = L.minimapToggle, order = 13, get = function() return not BigWigsIconDB.hide end, set = function(_, v) if v then BigWigsIconDB.hide = nil ldbi:Show("BigWigs") else BigWigsIconDB.hide = true ldbi:Hide("BigWigs") end end, width = "full", }, separator2 = { type = "description", name = " ", order = 14, width = "full", }, flash = { type = "toggle", name = L.flashScreen, desc = L.flashScreenDesc, order = 22, }, separator3 = { type = "description", name = " ", order = 30, width = "full", }, showZoneMessages = { type = "toggle", name = L.zoneMessages, desc = L.zoneMessagesDesc, order = 32, width = "full", }, separator4 = { type = "description", name = " ", order = 40, width = "full", }, fakeDBMVersion = { type = "toggle", name = L.dbmFaker, desc = L.dbmFakerDesc, order = 41, width = "full", }, slashDescTitle = { type = "description", name = "\n".. L.slashDescTitle, fontSize = "large", order = 43, width = "full", }, slashDescPull = { type = "description", name = " ".. L.slashDescPull, fontSize = "medium", order = 44, width = "full", }, slashDescBreak = { type = "description", name = " ".. L.slashDescBreak, fontSize = "medium", order = 45, width = "full", }, slashDescBar = { type = "description", name = " ".. L.slashDescRaidBar, fontSize = "medium", order = 46, width = "full", }, slashDescLocalBar = { type = "description", name = " ".. L.slashDescLocalBar, fontSize = "medium", order = 47, width = "full", }, slashDescRange = { type = "description", name = " ".. L.slashDescRange, fontSize = "medium", order = 48, width = "full", }, slashDescVersion = { type = "description", name = " ".. L.slashDescVersion, fontSize = "medium", order = 49, width = "full", }, slashDescConfig = { type = "description", name = " ".. L.slashDescConfig, fontSize = "medium", order = 50, width = "full", }, gitHubDesc = { type = "description", name = "\n".. L.gitHubDesc .."\n", fontSize = "medium", order = 51, width = "full", }, discord = { type = "input", get = function() return "discord.gg/jGveg85" end, set = function() end, name = "Discord", order = 52, width = 0.75, }, github = { type = "input", get = function() return "github.com/BigWigsMods" end, set = function() end, name = "GitHub", order = 53, width = 0.95, }, curseforge = { type = "input", get = function() return "curseforge.com/wow/addons/big-wigs" end, set = function() end, name = "CurseForge", order = 54, width = 1.32, }, }, }, }, } do local addonName = ... local f = CreateFrame("Frame") f:RegisterEvent("ADDON_LOADED") local function Initialize(_, _, addon) if addon ~= addonName then return end f:UnregisterEvent("ADDON_LOADED") acOptions.args.general.args.profileOptions = adbo:GetOptionsTable(BigWigs.db) acOptions.args.general.args.profileOptions.order = 100 acOptions.args.general.args.profileOptions.name = "|TInterface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Profile:20|t " .. acOptions.args.general.args.profileOptions.name lds:EnhanceOptions(acOptions.args.general.args.profileOptions, BigWigs.db) acr:RegisterOptionsTable("BigWigs", getOptions, true) acd:SetDefaultSize("BigWigs", 858, 660) acr.RegisterCallback(options, "ConfigTableChange") colorModule = BigWigs:GetPlugin("Colors") soundModule = BigWigs:GetPlugin("Sounds") acr:RegisterOptionsTable("BigWigs: Colors Override", colorModule:SetColorOptions("dummy", "dummy"), true) acr:RegisterOptionsTable("BigWigs: Sounds Override", soundModule:SetSoundOptions("dummy", "dummy"), true) loader.RegisterMessage(options, "BigWigs_BossModuleRegistered", "Register") loader.RegisterMessage(options, "BigWigs_PluginRegistered", "Register") for name, module in BigWigs:IterateBossModules() do options:Register("BigWigs_BossModuleRegistered", name, module) end for name, module in BigWigs:IteratePlugins() do options:Register("BigWigs_PluginRegistered", name, module) end loader.RegisterMessage(options, "BigWigs_StartConfigureMode") loader.RegisterMessage(options, "BigWigs_StopConfigureMode") -- Wait with nilling, we don't know how many addons will load during this same execution. loader.CTimerAfter(5, function() f:SetScript("OnEvent", nil) end) end f:SetScript("OnEvent", Initialize) end function options:Open() if not configFrame then options:OpenConfig() end end function options:Close() if configFrame then configFrame:Hide() end end function options:IsOpen() return configFrame and true or false end ------------------------------------------------------------------------------- -- Plugin options -- do local configMode = nil function options:InConfigureMode() return configMode end function options:BigWigs_StartConfigureMode() configMode = true end function options:BigWigs_StopConfigureMode() configMode = nil end end local function getMasterOption(self) local key = self:GetUserData("key") local module = self:GetUserData("module") if type(key) == "string" and key:find("^custom_") then return module.db.profile[key] end if type(module.db.profile[key]) ~= "number" then module.db.profile[key] = module.toggleDefaults[key] end if module.db.profile[key] == 0 then return false -- nothing go away end if bit.band(module.db.profile[key], module.toggleDefaults[key]) == module.toggleDefaults[key] then return true -- all default baby end return nil -- some options set end local notNumberError = "The option %q for module %q either has a mismatched current value (%q) or target value (%q)." local function getSlaveOption(self) local key = self:GetUserData("key") local module = self:GetUserData("module") local flag = self:GetUserData("flag") local current = module.db.profile[key] if type(current) ~= "number" or type(flag) ~= "number" then error(notNumberError:format(tostringall(key, module.moduleName, current, flag))) end return bit.band(current, flag) == flag end local function masterOptionToggled(self, event, value) if value == nil then self:SetValue(false) end -- toggling the master toggles all (we just pretend to be a tristate) local key = self:GetUserData("key") local module = self:GetUserData("module") if type(key) == "string" and key:find("custom_", nil, true) then module.db.profile[key] = value or false else if value then -- If an option is disabled by default using the "OFF" toggle flag, then when we turn it on, we want all the default flags on also module.db.profile[key] = module.toggleDisabled and module.toggleDisabled[key] or module.toggleDefaults[key] else module.db.profile[key] = 0 end local dropdown = self:GetUserData("dropdown") -- This data ONLY exists if we're looking at the advanced options tab, -- we force a refresh of all checkboxes when enabling/disabling the master option. if dropdown then local scrollFrame = self:GetUserData("scrollFrame") local bossOption = self:GetUserData("option") scrollFrame:ReleaseChildren() scrollFrame:AddChildren(getAdvancedToggleOption(scrollFrame, dropdown, module, bossOption)) scrollFrame:PerformLayout() end end -- After :SetValue so it's not overwritten self.text:SetTextColor(1, 0.82, 0) end local function slaveOptionToggled(self, event, value) local key = self:GetUserData("key") local module = self:GetUserData("module") local flag = self:GetUserData("flag") local master = self:GetUserData("master") if value then module.db.profile[key] = module.db.profile[key] + flag else module.db.profile[key] = module.db.profile[key] - flag end master:SetValue(getMasterOption(master)) -- After :SetValue so it's not overwritten master.text:SetTextColor(1, 0.82, 0) self.text:SetTextColor(1, 0.82, 0) end local function slaveOptionMouseOver(self, event, value) bwTooltip:SetOwner(self.frame, "ANCHOR_TOP") if self:GetUserData("label") then bwTooltip:AddLine(self:GetUserData("label")) end bwTooltip:AddLine(self:GetUserData("desc"), 1, 1, 1, true) bwTooltip:Show() end local function slaveOptionMouseLeave() bwTooltip:Hide() end local function getSlaveToggle(label, desc, key, module, flag, master, icon, ...) local toggle = AceGUI:Create("CheckBox") toggle:SetLabel(label) -- Flags to have at half width if flag == C.PULSE then toggle:SetRelativeWidth(0.5) elseif flag == C.ME_ONLY or flag == C.ME_ONLY_EMPHASIZE or flag == C.CASTBAR then toggle:SetRelativeWidth(0.4) else toggle:SetRelativeWidth(0.3) end toggle:SetHeight(30) if icon then if ... then toggle:SetImage(icon, ...) else if type(icon) == "string" then toggle:SetImage(icon) -- custom icon toggle:SetUserData("label", "|T"..icon..":20|t "..label) else toggle:SetImage(icon, 0.07, 0.93, 0.07, 0.93) end end end toggle:SetUserData("key", key) toggle:SetUserData("desc", desc) toggle:SetUserData("module", module) toggle:SetUserData("flag", flag) toggle:SetUserData("master", master) toggle:SetCallback("OnValueChanged", slaveOptionToggled) toggle:SetCallback("OnEnter", slaveOptionMouseOver) toggle:SetCallback("OnLeave", slaveOptionMouseLeave) toggle:SetValue(getSlaveOption(toggle)) toggle.text:SetTextColor(1, 0.82, 0) -- After :SetValue so it's not overwritten return toggle end local icons = { MESSAGE = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Messages", ME_ONLY = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\MeOnly", SOUND = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Sounds", ICON = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Markers", FLASH = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Flash", PULSE = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Pulse", PROXIMITY = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Proximity", ALTPOWER = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\AltPower", INFOBOX = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Info", COUNTDOWN = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Countdown", SAY = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Say", SAY_COUNTDOWN = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\SayCountdown", VOICE = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Voice", BAR = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Bars", CASTBAR = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Bars", NAMEPLATEBAR = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Bars", TANK = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Role_Tank", HEALER = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Role_Healer", EMPHASIZE = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\EmphasizeMessage", ME_ONLY_EMPHASIZE = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\EmphasizeMessageMeOnly", DISPEL = "Interface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Dispel", } local function hasOptionFlag(dbKey, module, key) -- Check the actual option table instead of using toggleDefaults for _, opTbl in next, module.toggleOptions do if type(opTbl) == "table" and opTbl[1] == dbKey then for i = 2, #opTbl do if opTbl[i] == key then return true end end end end end local function advancedToggles(dbKey, module, check) local dbv = module.toggleDisabled and module.toggleDisabled[dbKey] or module.toggleDefaults[dbKey] local advancedOptions = {} if bit.band(dbv, C.MESSAGE) == C.MESSAGE then -- Emphasize & Countdown widgets advancedOptions[1] = getSlaveToggle(L.EMPHASIZE, L.EMPHASIZE_desc, dbKey, module, C.EMPHASIZE, check, icons.EMPHASIZE) advancedOptions[2] = getSlaveToggle(L.ME_ONLY_EMPHASIZE, L.ME_ONLY_EMPHASIZE_desc, dbKey, module, C.ME_ONLY_EMPHASIZE, check, icons.ME_ONLY_EMPHASIZE) advancedOptions[3] = getSlaveToggle(L.COUNTDOWN, L.COUNTDOWN_desc, dbKey, module, C.COUNTDOWN, check, icons.COUNTDOWN) -- -- Messages & Sound advancedOptions[4] = getSlaveToggle(L.MESSAGE, L.MESSAGE_desc, dbKey, module, C.MESSAGE, check, icons.MESSAGE) advancedOptions[5] = getSlaveToggle(L.ME_ONLY, L.ME_ONLY_desc, dbKey, module, C.ME_ONLY, check, icons.ME_ONLY) advancedOptions[6] = getSlaveToggle(L.SOUND, L.SOUND_desc, dbKey, module, C.SOUND, check, icons.SOUND) -- -- Bars advancedOptions[7] = getSlaveToggle(L.BAR, L.BAR_desc, dbKey, module, C.BAR, check, icons.BAR) advancedOptions[8] = getSlaveToggle(L.CASTBAR, L.CASTBAR_desc, dbKey, module, C.CASTBAR, check, icons.CASTBAR) -- end if bit.band(dbv, C.NAMEPLATEBAR) == C.NAMEPLATEBAR and hasOptionFlag(dbKey, module, "NAMEPLATEBAR") then advancedOptions[#advancedOptions + 1] = getSlaveToggle(L.NAMEPLATEBAR, L.NAMEPLATEBAR_desc, dbKey, module, C.NAMEPLATEBAR, check, icons.NAMEPLATEBAR) end -- Flash & Pulse if bit.band(dbv, C.FLASH) == C.FLASH and hasOptionFlag(dbKey, module, "FLASH") then advancedOptions[#advancedOptions + 1] = getSlaveToggle(L.FLASH, L.FLASH_desc, dbKey, module, C.FLASH, check, icons.FLASH) advancedOptions[#advancedOptions + 1] = getSlaveToggle(L.PULSE, L.PULSE_desc, dbKey, module, C.PULSE, check, icons.PULSE) end -- if bit.band(dbv, C.MESSAGE) == C.MESSAGE then if API:HasVoicePack() then advancedOptions[#advancedOptions + 1] = getSlaveToggle(L.VOICE, L.VOICE_desc, dbKey, module, C.VOICE, check, icons.VOICE) end end for i, key in next, BigWigs:GetOptions() do local flag = C[key] if bit.band(dbv, flag) == flag then local name, desc = BigWigs:GetOptionDetails(key) -- All on by default, check if we should add a GUI widget if key == "ICON" or key == "SAY" or key == "SAY_COUNTDOWN" or key == "PROXIMITY" or key == "ALTPOWER" or key == "INFOBOX" then if hasOptionFlag(dbKey, module, key) then advancedOptions[#advancedOptions + 1] = getSlaveToggle(name, desc, dbKey, module, flag, check, icons[key]) end elseif key ~= "MESSAGE" and key ~= "BAR" and key ~= "FLASH" and key ~= "VOICE" then advancedOptions[#advancedOptions + 1] = getSlaveToggle(name, desc, dbKey, module, flag, check) end end end return unpack(advancedOptions) end local function advancedTabSelect(widget, callback, tab) if widget:GetUserData("tab") == tab then return end widget:SetUserData("tab", tab) widget:PauseLayout() widget:ReleaseChildren() local module = widget:GetUserData("module") local key = widget:GetUserData("key") local master = widget:GetUserData("master") if tab == "options" then widget:AddChildren(advancedToggles(key, module, master)) elseif tab == "sounds" then local group = AceGUI:Create("SimpleGroup") group:SetFullWidth(true) widget:AddChild(group) soundModule:SetSoundOptions(module.name, key, module.db.profile[key]) acd:Open("BigWigs: Sounds Override", group) elseif tab == "colors" then local group = AceGUI:Create("SimpleGroup") group:SetFullWidth(true) widget:AddChild(group) colorModule:SetColorOptions(module.name, key, module.toggleDefaults[key]) acd:Open("BigWigs: Colors Override", group) end widget:ResumeLayout() widget:GetUserData("scrollFrame"):PerformLayout() widget:PerformLayout() end local advancedTabs = { { text = "|TInterface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Sliders:20|t ".. L.advanced, value = "options", }, { text = "|TInterface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Colors:20|t ".. L.colors, value = "colors", }, { text = "|TInterface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Sounds:20|t ".. L.sound, value = "sounds", }, } function getAdvancedToggleOption(scrollFrame, dropdown, module, bossOption) local dbKey, name, desc, icon, alternativeName = BigWigs:GetBossOptionDetails(module, bossOption) local back = AceGUI:Create("Button") back:SetText(L.back) back:SetFullWidth(true) back:SetCallback("OnClick", function() showToggleOptions(dropdown, nil, dropdown:GetUserData("bossIndex")) end) local check = AceGUI:Create("CheckBox") check:SetLabel(alternativeName and L.alternativeName:format(name, alternativeName) or name) check:SetTriState(true) check:SetFullWidth(true) check:SetDescription(desc) check:SetUserData("key", dbKey) check:SetUserData("scrollFrame", scrollFrame) check:SetUserData("dropdown", dropdown) check:SetUserData("module", module) check:SetUserData("option", bossOption) check:SetCallback("OnValueChanged", masterOptionToggled) check:SetValue(getMasterOption(check)) check.text:SetTextColor(1, 0.82, 0) -- After :SetValue so it's not overwritten if icon then check:SetImage(icon, 0.07, 0.93, 0.07, 0.93) end -- Create role-specific secondary checkbox local roleRestrictionCheckbox = nil for i, key in next, BigWigs:GetRoleOptions() do local flag = C[key] local dbv = module.toggleDisabled and module.toggleDisabled[dbKey] or module.toggleDefaults[dbKey] if bit.band(dbv, flag) == flag then local roleName, roleDesc = BigWigs:GetOptionDetails(key) if key == "TANK" then roleRestrictionCheckbox = getSlaveToggle(roleName, roleDesc, dbKey, module, flag, check, icons.TANK) elseif key == "HEALER" then roleRestrictionCheckbox = getSlaveToggle(roleName, roleDesc, dbKey, module, flag, check, icons.HEALER) elseif key == "DISPEL" then roleRestrictionCheckbox = getSlaveToggle(roleName, roleDesc, dbKey, module, flag, check, icons.DISPEL) else roleRestrictionCheckbox = getSlaveToggle(roleName, roleDesc, dbKey, module, flag, check) -- No icon end roleRestrictionCheckbox:SetDescription(roleDesc) roleRestrictionCheckbox:SetFullWidth(true) roleRestrictionCheckbox:SetUserData("desc", nil) -- Remove tooltip set by getSlaveToggle() function end end local tabs = AceGUI:Create("TabGroup") tabs:SetLayout("Flow") tabs:SetTabs(advancedTabs) tabs:SetFullWidth(true) tabs:SetCallback("OnGroupSelected", advancedTabSelect) tabs:SetUserData("tab", "") tabs:SetUserData("key", dbKey) tabs:SetUserData("module", module) tabs:SetUserData("master", check) tabs:SetUserData("scrollFrame", scrollFrame) tabs:SelectTab("options") if roleRestrictionCheckbox then return back, check, roleRestrictionCheckbox, tabs else return back, check, tabs end end local spellUpdater = CreateFrame("Frame") local needsUpdate, needsLayout = {}, {} local function RefreshOnUpdate(self) local scrollFrame = nil for widget in next, needsLayout do needsLayout[widget] = nil scrollFrame = widget:GetUserData("scrollFrame") local module, bossOption = widget:GetUserData("module"), widget:GetUserData("option") local _, _, desc = BigWigs:GetBossOptionDetails(module, bossOption) widget:SetDescription(desc) end if scrollFrame then scrollFrame:PerformLayout() end self:SetScript("OnUpdate", nil) end spellUpdater:SetScript("OnEvent", function(self, event, spellId, success) if success and needsUpdate[spellId] then needsLayout[needsUpdate[spellId]] = true local desc = GetSpellDescription(spellId) self:SetScript("OnUpdate", RefreshOnUpdate) end needsUpdate[spellId] = nil end) spellUpdater:RegisterEvent("SPELL_DATA_LOAD_RESULT") local function clearPendingUpdates() spellUpdater:SetScript("OnUpdate", nil) needsUpdate = {} needsLayout = {} end local function buttonClicked(widget) clearPendingUpdates() local scrollFrame = widget:GetUserData("scrollFrame") local dropdown = widget:GetUserData("dropdown") local module = widget:GetUserData("module") local bossOption = widget:GetUserData("bossOption") scrollFrame:ReleaseChildren() scrollFrame:SetScroll(0) scrollFrame:AddChildren(getAdvancedToggleOption(scrollFrame, dropdown, module, bossOption)) scrollFrame:PerformLayout() end local function flagOnEnter(widget) bwTooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT") bwTooltip:SetText(widget:GetUserData("tooltipText"), 1, 1, 1, true) bwTooltip:Show() end local function flagOnLeave() bwTooltip:Hide() end local function getDefaultToggleOption(scrollFrame, dropdown, module, bossOption) local dbKey, name, desc, icon, alternativeName = BigWigs:GetBossOptionDetails(module, bossOption) -- jesus this is so hacky. should probably be "custom_select_" with values as a -- :GetBossOptionDetails return, but this keeps changes to a minimum for now if type(dbKey) == "string" and dbKey:find("^custom_off_select_") then local L = module:GetLocale() local values = { [0] = _G.ADDON_DISABLED } local i = 1 local value = L[dbKey.."_value"..i] repeat values[i] = value i = i + 1 value = L[dbKey.."_value"..i] until not value local dropdown = AceGUI:Create("Dropdown") if desc then -- The label will truncate at ~74 chars, but showing the desc in a tooltip seems awkward dropdown:SetLabel(("%s: |cffffffff%s|r"):format(name, desc)) else dropdown:SetLabel(name) end dropdown:SetMultiselect(false) dropdown:SetList(values) dropdown:SetFullWidth(true) dropdown:SetUserData("key", dbKey) dropdown:SetUserData("module", module) dropdown:SetCallback("OnValueChanged", function(widget, _, value) if value == 0 then value = false end local key = widget:GetUserData("key") local module = widget:GetUserData("module") module.db.profile[key] = value or false end) dropdown:SetValue(module.db.profile[dbKey] or 0) return dropdown end local check = AceGUI:Create("CheckBox") check:SetLabel(alternativeName and L.alternativeName:format(name, alternativeName) or name) check:SetTriState(true) check:SetRelativeWidth(0.85) check:SetUserData("key", dbKey) check:SetUserData("module", module) check:SetUserData("option", bossOption) check:SetUserData("scrollFrame", scrollFrame) check:SetDescription(desc) check:SetCallback("OnValueChanged", masterOptionToggled) check:SetValue(getMasterOption(check)) check.text:SetTextColor(1, 0.82, 0) -- After :SetValue so it's not overwritten if icon then check:SetImage(icon, 0.07, 0.93, 0.07, 0.93) end local spellId = nil if type(dbKey) == "number" then if dbKey < 0 then -- the "why did you use an ej id instead of the spell directly" check -- headers and other non-spell entries don't load async local info = C_EncounterJournal.GetSectionInfo(-dbKey) if info.spellID > 0 then spellId = info.spellID end else spellId = dbKey end else local L = module:GetLocale(true) local title, description = L[dbKey], L[dbKey .. "_desc"] if type(title) == "number" and not description then spellId = title elseif type(description) == "number" then spellId = description end end if spellId and not C_Spell.IsSpellDataCached(spellId) then needsUpdate[spellId] = check C_Spell.RequestLoadSpellData(spellId) end if type(dbKey) == "string" and dbKey:find("^custom_") then return check end local flagIcons = {} local showFlags = { "TANK_HEALER", "TANK", "HEALER", "DISPEL", "EMPHASIZE", "ME_ONLY", "ME_ONLY_EMPHASIZE", "COUNTDOWN", "FLASH", "ICON", "SAY", "SAY_COUNTDOWN", "PROXIMITY", "INFOBOX", "ALTPOWER", "NAMEPLATEBAR", } for i = 1, #showFlags do local key = showFlags[i] if hasOptionFlag(dbKey, module, key) then local icon = AceGUI:Create("Icon") icon:SetWidth(16) icon:SetImageSize(16, 16) icon:SetUserData("tooltipText", L[key]) icon:SetCallback("OnEnter", flagOnEnter) icon:SetCallback("OnLeave", flagOnLeave) if key == "TANK_HEALER" then -- add both "TANK" and "HEALER" icons local icon1 = AceGUI:Create("Icon") icon1:SetWidth(16) icon1:SetImage(icons.TANK) icon1:SetImageSize(16, 16) icon1:SetUserData("tooltipText", L[key]) icon1:SetCallback("OnEnter", flagOnEnter) icon1:SetCallback("OnLeave", flagOnLeave) icon1.frame:SetParent(check.frame) icon1.frame:Show() flagIcons[#flagIcons+1] = icon1 -- first icon, don't bother with SetPoint icon:SetImage(icons.HEALER) else if type(icons[key]) == "string" then icon:SetImage(icons[key]) -- custom icon else icon:SetImage(icons[key], 0.07, 0.93, 0.07, 0.93) end end icon.frame:SetParent(check.frame) icon.frame:Show() flagIcons[#flagIcons+1] = icon if #flagIcons > 1 then icon:SetPoint("LEFT", flagIcons[#flagIcons-1].frame, "RIGHT", 1, 0) end end end if #flagIcons > 0 then -- flagIcons[1]:SetPoint("LEFT", check.text, "RIGHT", -(#flagIcons * (16+1)) - 30, 0) flagIcons[1]:SetPoint("LEFT", check.text, "LEFT", check.text:GetStringWidth() + 5, 0) -- need to clean these up since they are not added to a container check:SetUserData("icons", flagIcons) check:SetCallback("OnRelease", function(widget) for _, icon in next, widget:GetUserData("icons") do icon:Release() end end) end local button = AceGUI:Create("Button") button:SetText(">>") button:SetRelativeWidth(0.15) button:SetUserData("scrollFrame", scrollFrame) button:SetUserData("dropdown", dropdown) button:SetUserData("module", module) button:SetUserData("bossOption", bossOption) button:SetCallback("OnClick", buttonClicked) return check, button end local listAbilitiesInChat = nil do local SendChatMessage = loader.SendChatMessage local function output(channel, ...) if channel then SendChatMessage(strjoin(" ", ...), channel) else print(...) end end local function printList(channel, header, list) if #list == 0 then return end if header then output(channel, header, unpack(list)) else output(channel, unpack(list)) end end function listAbilitiesInChat(widget) local module = widget:GetUserData("module") local channel = IsInGroup(2) and "INSTANCE_CHAT" or IsInRaid() and "RAID" or IsInGroup() and "PARTY" local abilities = {} local header = nil output(channel, "BigWigs: ", module.displayName or module.moduleName or module.name) local currentSize = 0 for i, option in next, module.toggleOptions do local o = type(option) == "table" and option[1] or option if module.optionHeaders and module.optionHeaders[o] then -- print what we have so far printList(channel, header, abilities) abilities = {} header = module.optionHeaders[o] currentSize = #header end local link if type(o) == "number" then if o > 0 then local spellLink = GetSpellLink(o) if not spellLink then local spellName = GetSpellInfo(o) link = ("\124cff71d5ff\124Hspell:%d:0\124h[%s]\124h\124r"):format(o, spellName) --BigWigs:Error(("Failed to fetch the link for spell id %d, tell the authors."):format(o)) else link = spellLink end else local tbl = C_EncounterJournal.GetSectionInfo(-o) if not tbl or not tbl.link then BigWigs:Error(("Failed to fetch the link for journal id (-)%d, tell the authors."):format(-o)) else link = tbl.link end end elseif type(o) == "string" then -- Attempt to build links for strings that are just basic spell renaming local L = module:GetLocale() if L then local name, desc, icon = L[o], L[o.."_desc"], L[o.."_icon"] if name and type(desc) == "number" and desc == icon then if desc > 0 then local spellName = GetSpellInfo(desc) link = ("\124cff71d5ff\124Hspell:%d:0\124h[%s]\124h\124r"):format(desc, spellName) else -- EJ? end end end end if link then if currentSize + #link + 1 > 255 then printList(channel, header, abilities) abilities = {} currentSize = 0 end abilities[#abilities + 1] = link currentSize = currentSize + #link + 1 end end printList(channel, header, abilities) end end local function SecondsToTime(time) local m = floor(time/60) local s = mod(time, 60) return ("%d:%02d"):format(m, s) end local function populateToggleOptions(widget, module) clearPendingUpdates() local scrollFrame = widget:GetUserData("parent") scrollFrame:ReleaseChildren() scrollFrame:PauseLayout() local id = module.instanceId local sDB = BigWigsStatsDB if module.journalId and id and id > 0 and BigWigs:GetPlugin("Statistics").db.profile.enabled and sDB and sDB[id] and sDB[id][module.journalId] then sDB = sDB[id][module.journalId] if next(sDB) then -- Create statistics table local statGroup = AceGUI:Create("InlineGroup") statGroup:SetTitle(L.statistics) statGroup:SetLayout("Flow") statGroup:SetFullWidth(true) scrollFrame:AddChild(statGroup) local statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText("") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(L.lfr) statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(L.normal) statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(L.heroic) statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(L.mythic) statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetFullWidth(true) statistics:SetText("") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(L.wipes) statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.LFR and sDB.LFR.wipes or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.normal and sDB.normal.wipes or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.heroic and sDB.heroic.wipes or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.mythic and sDB.mythic.wipes or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetFullWidth(true) statistics:SetText("") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(L.kills) statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.LFR and sDB.LFR.kills or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.normal and sDB.normal.kills or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.heroic and sDB.heroic.kills or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.mythic and sDB.mythic.kills or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetFullWidth(true) statistics:SetText("") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(L.best) statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.LFR and sDB.LFR.best and SecondsToTime(sDB.LFR.best) or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.normal and sDB.normal.best and SecondsToTime(sDB.normal.best) or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.heroic and sDB.heroic.best and SecondsToTime(sDB.heroic.best) or "-") statGroup:AddChild(statistics) statistics = AceGUI:Create("Label") statistics:SetWidth(100) statistics:SetText(sDB.mythic and sDB.mythic.best and SecondsToTime(sDB.mythic.best) or "-") statGroup:AddChild(statistics) end -- End statistics table end if module.SetupOptions then module:SetupOptions() end for i, option in next, module.toggleOptions do local o = option if type(o) == "table" then o = option[1] end if module.optionHeaders and module.optionHeaders[o] then local header = AceGUI:Create("Heading") header:SetText(module.optionHeaders[o]) header:SetFullWidth(true) scrollFrame:AddChild(header) end scrollFrame:AddChildren(getDefaultToggleOption(scrollFrame, widget, module, option)) end local list = AceGUI:Create("Button") list:SetFullWidth(true) list:SetText(L.listAbilities) list:SetUserData("module", module) list:SetCallback("OnClick", listAbilitiesInChat) scrollFrame:AddChild(list) scrollFrame:SetScroll(0) scrollFrame:ResumeLayout() scrollFrame:PerformLayout() end function showToggleOptions(widget, event, group) local module = BigWigs:GetBossModule(group) widget:SetUserData("bossIndex", group) populateToggleOptions(widget, module) end local function onZoneShow(treeWidget, id) -- Make sure all the bosses for this zone are loaded. loader:LoadZone(id) -- Grab the module list from this zone local moduleList = loader:GetZoneMenus()[id] if type(moduleList) ~= "table" then return end -- No modules registered local zoneList, zoneSort = {}, {} for i = 1, #moduleList do local module = moduleList[i] zoneList[module.moduleName] = module.displayName zoneSort[i] = module.moduleName end local outerContainer = AceGUI:Create("SimpleGroup") outerContainer:PauseLayout() -- Stop drawing (improves performance) until we've added everything outerContainer:SetLayout("Fill") outerContainer:SetFullWidth(true) treeWidget:AddChild(outerContainer) local innerContainer = AceGUI:Create("DropdownGroup") innerContainer:SetTitle(L.selectEncounter) innerContainer:SetLayout("Flow") innerContainer:SetCallback("OnGroupSelected", showToggleOptions) innerContainer:SetUserData("zone", id) innerContainer:SetGroupList(zoneList, zoneSort) -- scroll is where we actually put stuff in case things -- overflow vertically local scroll = AceGUI:Create("ScrollFrame") scroll:SetLayout("Flow") scroll:SetFullWidth(true) scroll:SetFullHeight(true) innerContainer:SetUserData("parent", scroll) innerContainer:AddChild(scroll) outerContainer:AddChild(innerContainer) outerContainer:ResumeLayout() outerContainer:PerformLayout() -- Everything added, gogo -- Find the first enabled module and select that in the dropdown if possible. local index = 1 for i = 1, #zoneSort do local name = zoneSort[i] local m = BigWigs:GetBossModule(name) if m:IsEnabled() and m.journalId then index = i break end end innerContainer:SetGroup(zoneSort[index]) innerContainer:DoLayout() -- One last refresh to adjust height end do local expansionHeader = { "Classic", "BurningCrusade", "WrathOfTheLichKing", "Cataclysm", "MistsOfPandaria", "WarlordsOfDraenor", "Legion", "BattleForAzeroth", "Shadowlands" } local statusTable = {} local playerName = nil local GetBestMapForUnit = loader.GetBestMapForUnit local GetMapInfo = loader.GetMapInfo local function onControlEnter(widget) bwTooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT") bwTooltip:SetText(widget.text:GetText(), 1, 0.82, 0, true) bwTooltip:AddLine(widget:GetUserData("desc"), 1, 1, 1, true) bwTooltip:Show() end local function onControlLeave() bwTooltip:Hide() end local function toggleAnchors(widget) if not BigWigs:IsEnabled() then BigWigs:Enable() end if options:InConfigureMode() then widget:SetText(L.toggleAnchorsBtnShow) widget:SetUserData("desc", L.toggleAnchorsBtnShow_desc) options:SendMessage("BigWigs_StopConfigureMode") else widget:SetText(L.toggleAnchorsBtnHide) widget:SetUserData("desc", L.toggleAnchorsBtnHide_desc) options:SendMessage("BigWigs_StartConfigureMode") end onControlLeave() onControlEnter(widget) end local function onTreeGroupSelected(widget, event, value) widget:ReleaseChildren() local zoneId = value:match("\001(-?%d+)$") if zoneId then onZoneShow(widget, tonumber(zoneId)) elseif value:match("^BigWigs_") and value ~= "BigWigs_Shadowlands" and GetAddOnEnableState(playerName, value) == 0 then local missing = AceGUI:Create("Label") missing:SetText(L.missingAddOn:format(value)) missing:SetFontObject(GameFontHighlight) missing:SetFullWidth(true) widget:AddChild(missing) elseif value:match("^LittleWigs_") and GetAddOnEnableState(playerName, "LittleWigs") == 0 then local missing = AceGUI:Create("Label") missing:SetText(L.missingAddOn:format("LittleWigs")) missing:SetFontObject(GameFontHighlight) missing:SetFullWidth(true) widget:AddChild(missing) else statusTable.groups[value] = true widget:RefreshTree() end end local function onTabGroupSelected(widget, event, value) widget:ReleaseChildren() if value == "options" then -- Embed the AceConfig options in our AceGUI frame local container = AceGUI:Create("SimpleGroup") container.type = "BigWigsOptions" -- We want ACD to create a ScrollFrame, so we change the type to bypass it's group control check container:SetFullHeight(true) container:SetFullWidth(true) -- Have to use :Open instead of just :FeedGroup because some widget types (range, color) call :Open to refresh on change isPluginOpen = container acd:Open("BigWigs", container) widget:AddChild(container) else isPluginOpen = nil local treeTbl = {} local addonNameToHeader = {} local defaultHeader if value == "bigwigs" then defaultHeader = "BigWigs_Shadowlands" for i = 1, 9 do local value = "BigWigs_" .. expansionHeader[i] treeTbl[i] = { text = EJ_GetTierInfo(i), value = value, enabled = (value == defaultHeader or GetAddOnEnableState(playerName, value) > 0), } addonNameToHeader[value] = i end elseif value == "littlewigs" then defaultHeader = "LittleWigs_Shadowlands" local enabled = GetAddOnEnableState(playerName, "LittleWigs") > 0 for i = 1, 9 do local value = "LittleWigs_" .. expansionHeader[i] treeTbl[i] = { text = EJ_GetTierInfo(i), value = value, enabled = enabled, } addonNameToHeader[value] = i end end do local zoneToId, alphabeticalZoneList = {}, {} for k in next, loader:GetZoneMenus() do local zone if k < 0 then local tbl = GetMapInfo(-k) if tbl then zone = tbl.name else zone = tostring(k) end else zone = GetRealZoneText(k) end if zone then if zoneToId[zone] then zone = zone .. "1" -- When instances exist more than once (Karazhan) end zoneToId[zone] = k alphabeticalZoneList[#alphabeticalZoneList+1] = zone end end sort(alphabeticalZoneList) -- Make alphabetical for i = 1, #alphabeticalZoneList do local zoneName = alphabeticalZoneList[i] local id = zoneToId[zoneName] local parent = loader.zoneTbl[id] and addonNameToHeader[loader.zoneTbl[id]] -- Get expansion number for this zone local treeParent = treeTbl[parent] -- Grab appropriate expansion name if treeParent and treeParent.enabled then -- third-party plugins can add empty zones if you don't have the expansion addon enabled if not treeParent.children then treeParent.children = {} end -- Create sub menu table tinsert(treeParent.children, { -- Add new instance/zone sub menu value = id, text = zoneName, }) end end end local tree = AceGUI:Create("TreeGroup") tree:SetFullWidth(true) tree:SetFullHeight(true) tree:SetStatusTable(statusTable) tree:SetTree(treeTbl) tree:SetLayout("Fill") tree:SetCallback("OnGroupSelected", onTreeGroupSelected) -- Do we have content for the zone we're in? Then open straight to that zone. local _, instanceType, _, _, _, _, _, id = loader.GetInstanceInfo() local parent = loader.zoneTbl[id] and addonNameToHeader[loader.zoneTbl[id]] if instanceType == "none" then local mapId = GetBestMapForUnit("player") if mapId then id = loader.zoneTblWorld[-mapId] parent = loader.zoneTbl[id] and addonNameToHeader[loader.zoneTbl[id]] end end if parent then local moduleList = id and loader:GetZoneMenus()[id] local value = treeTbl[parent].value tree:SelectByValue(moduleList and ("%s\001%d"):format(value, id) or value) else tree:SelectByValue(defaultHeader) end widget:AddChild(tree) end end function options:OpenConfig() playerName = UnitName("player") local bw = AceGUI:Create("Frame") configFrame = bw bw:SetTitle("BigWigs") bw:SetStatusText(" "..loader:GetReleaseString()) bw:SetWidth(858) bw:SetHeight(660) bw:EnableResize(false) bw:SetLayout("Flow") bw:SetCallback("OnClose", function(widget) AceGUI:Release(widget) statusTable = {} isPluginOpen = nil configFrame = nil end) --local anchors = AceGUI:Create("Button") --if self:InConfigureMode() then -- anchors:SetText(L.toggleAnchorsBtnHide) -- anchors:SetUserData("desc", L.toggleAnchorsBtnHide_desc) --else -- anchors:SetText(L.toggleAnchorsBtnShow) -- anchors:SetUserData("desc", L.toggleAnchorsBtnShow_desc) --end --anchors:SetRelativeWidth(0.5) --anchors:SetCallback("OnClick", toggleAnchors) --anchors:SetCallback("OnEnter", onControlEnter) --anchors:SetCallback("OnLeave", onControlLeave) -- --local testing = AceGUI:Create("Button") --testing:SetText(L.testBarsBtn) --testing:SetUserData("desc", L.testBarsBtn_desc) --testing:SetRelativeWidth(0.5) --testing:SetCallback("OnClick", BigWigs.Test) --testing:SetCallback("OnEnter", onControlEnter) --testing:SetCallback("OnLeave", onControlLeave) -- --bw:AddChildren(anchors, testing) local tabs = AceGUI:Create("TabGroup") tabs:SetLayout("Flow") tabs:SetFullWidth(true) tabs:SetFullHeight(true) tabs:SetTabs({ { text = L.options, value = "options" }, { text = L.raidBosses, value = "bigwigs" }, { text = L.dungeonBosses, value = "littlewigs" }, }) tabs:SetCallback("OnGroupSelected", onTabGroupSelected) tabs:SelectTab("options") bw:AddChild(tabs) bw:Show() end end do local registered, subPanelRegistry, pluginRegistry = {}, {}, {} function options:Register(_, _, module) if registered[module.name] then return end registered[module.name] = true if module.pluginOptions then if type(module.pluginOptions) == "function" then pluginRegistry[module.name] = module.pluginOptions else acOptions.args.general.args[module.name] = module.pluginOptions end elseif module.subPanelOptions then local key = module.subPanelOptions.key local opts = module.subPanelOptions.options if type(opts) == "function" then subPanelRegistry[key] = opts else acOptions.args[key] = opts end end end function getOptions() for key, opts in next, pluginRegistry do acOptions.args.general.args[key] = opts() end for key, opts in next, subPanelRegistry do acOptions.args[key] = opts() end return acOptions end end function options:ConfigTableChange(_, appName) if appName == "BigWigs" and isPluginOpen then acd:Open("BigWigs", isPluginOpen) end end BigWigsOptions = options -- Set global