407 lines
13 KiB
Lua
407 lines
13 KiB
Lua
--[[
|
|
~AddOn Engine~
|
|
|
|
To load the AddOn engine add this to the top of your file:
|
|
|
|
local E, L, V, P, G = unpack(select(2, ...)); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
|
|
]]
|
|
|
|
--Lua functions
|
|
local _G, min, pairs, strsplit, unpack, wipe, type, tcopy = _G, min, pairs, strsplit, unpack, wipe, type, table.copy
|
|
--WoW API / Variables
|
|
local hooksecurefunc = hooksecurefunc
|
|
local CreateFrame = CreateFrame
|
|
local GetAddOnInfo = GetAddOnInfo
|
|
local GetAddOnMetadata = GetAddOnMetadata
|
|
local GetTime = GetTime
|
|
local HideUIPanel = HideUIPanel
|
|
local InCombatLockdown = InCombatLockdown
|
|
local IsAddOnLoaded = IsAddOnLoaded
|
|
local LoadAddOn = LoadAddOn
|
|
local ReloadUI = ReloadUI
|
|
local EscapeMenu = EscapeMenu
|
|
|
|
local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
|
|
|
|
BINDING_HEADER_ELVUI = GetAddOnMetadata(..., "Title")
|
|
|
|
local AceAddon, AceAddonMinor = LibStub("AceAddon-3.0")
|
|
local CallbackHandler = LibStub("CallbackHandler-1.0")
|
|
|
|
local AddOnName, Engine = ...
|
|
local AddOn = LibStub("AceAddon-3.0"):NewAddon(AddOnName, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0", "AceHook-3.0")
|
|
AddOn.callbacks = AddOn.callbacks or CallbackHandler:New(AddOn)
|
|
AddOn.DF = {profile = {}, global = {}}; AddOn.privateVars = {profile = {}} -- Defaults
|
|
AddOn.Options = {type = "group", name = AddOnName, args = {}}
|
|
|
|
Engine[1] = AddOn
|
|
Engine[2] = {}
|
|
Engine[3] = AddOn.privateVars.profile
|
|
Engine[4] = AddOn.DF.profile
|
|
Engine[5] = AddOn.DF.global
|
|
_G[AddOnName] = Engine
|
|
|
|
do
|
|
AddOn.Libs = {}
|
|
AddOn.LibsMinor = {}
|
|
function AddOn:AddLib(name, major, minor)
|
|
if not name then return end
|
|
|
|
-- in this case: `major` is the lib table and `minor` is the minor version
|
|
if type(major) == "table" and type(minor) == "number" then
|
|
self.Libs[name], self.LibsMinor[name] = major, minor
|
|
else -- in this case: `major` is the lib name and `minor` is the silent switch
|
|
self.Libs[name], self.LibsMinor[name] = LibStub(major, minor)
|
|
end
|
|
end
|
|
|
|
AddOn:AddLib("AceAddon", AceAddon, AceAddonMinor)
|
|
AddOn:AddLib("AceDB", "AceDB-3.0")
|
|
AddOn:AddLib("EP", "LibElvUIPlugin-1.0")
|
|
AddOn:AddLib("LSM", "LibSharedMedia-3.0")
|
|
AddOn:AddLib("ACL", "AceLocale-3.0-ElvUI")
|
|
AddOn:AddLib('ACH', 'LibAceConfigHelper')
|
|
AddOn:AddLib("LAB", "LibActionButton-1.0-ElvUI")
|
|
AddOn:AddLib("LAI", "LibAuraInfo-1.0-ElvUI", true)
|
|
AddOn:AddLib("LBF", "LibButtonFacade", true)
|
|
AddOn:AddLib("LDB", "LibDataBroker-1.1")
|
|
AddOn:AddLib("DualSpec", "LibDualSpec-1.0")
|
|
AddOn:AddLib("SimpleSticky", "LibSimpleSticky-1.0")
|
|
AddOn:AddLib("SpellRange", "SpellRange-1.0")
|
|
AddOn:AddLib("ItemSearch", "LibItemSearch-1.2-ElvUI")
|
|
AddOn:AddLib("Compress", "LibCompress")
|
|
AddOn:AddLib('Deflate', 'LibDeflate')
|
|
AddOn:AddLib("Base64", "LibBase64-1.0-ElvUI")
|
|
AddOn:AddLib("Translit", "LibTranslit-1.0")
|
|
-- added on ElvUI_OptionsUI load: AceGUI, AceConfig, AceConfigDialog, AceConfigRegistry, AceDBOptions
|
|
|
|
-- backwards compatible for plugins
|
|
AddOn.LSM = AddOn.Libs.LSM
|
|
AddOn.Masque = AddOn.Libs.Masque
|
|
end
|
|
|
|
AddOn.oUF = Engine.oUF
|
|
AddOn.ActionBars = AddOn:NewModule("ActionBars","AceHook-3.0","AceEvent-3.0")
|
|
AddOn.AFK = AddOn:NewModule("AFK","AceEvent-3.0","AceTimer-3.0")
|
|
AddOn.Auras = AddOn:NewModule("Auras","AceHook-3.0","AceEvent-3.0")
|
|
AddOn.Bags = AddOn:NewModule("Bags","AceHook-3.0","AceEvent-3.0","AceTimer-3.0", "AceBucket-3.0")
|
|
AddOn.Blizzard = AddOn:NewModule("Blizzard","AceEvent-3.0","AceHook-3.0")
|
|
AddOn.Chat = AddOn:NewModule("Chat","AceTimer-3.0","AceHook-3.0","AceEvent-3.0")
|
|
AddOn.DataBars = AddOn:NewModule("DataBars","AceEvent-3.0")
|
|
AddOn.DataTexts = AddOn:NewModule("DataTexts","AceTimer-3.0","AceHook-3.0","AceEvent-3.0", "AceBucket-3.0")
|
|
AddOn.DebugTools = AddOn:NewModule("DebugTools","AceEvent-3.0","AceHook-3.0")
|
|
AddOn.Distributor = AddOn:NewModule("Distributor","AceEvent-3.0","AceTimer-3.0","AceComm-3.0","AceSerializer-3.0")
|
|
AddOn.Layout = AddOn:NewModule("Layout","AceEvent-3.0")
|
|
AddOn.Minimap = AddOn:NewModule("Minimap","AceEvent-3.0")
|
|
AddOn.Misc = AddOn:NewModule("Misc","AceEvent-3.0","AceTimer-3.0")
|
|
AddOn.ModuleCopy = AddOn:NewModule("ModuleCopy","AceEvent-3.0","AceTimer-3.0","AceComm-3.0","AceSerializer-3.0")
|
|
AddOn.NamePlates = AddOn:NewModule("NamePlates","AceHook-3.0","AceEvent-3.0","AceTimer-3.0")
|
|
AddOn.PluginInstaller = AddOn:NewModule("PluginInstaller")
|
|
AddOn.RaidUtility = AddOn:NewModule("RaidUtility","AceEvent-3.0")
|
|
AddOn.ReminderBuffs = AddOn:NewModule("ReminderBuffs", "AceEvent-3.0")
|
|
AddOn.Skins = AddOn:NewModule("Skins","AceTimer-3.0","AceHook-3.0","AceEvent-3.0")
|
|
AddOn.Threat = AddOn:NewModule("Threat","AceEvent-3.0")
|
|
AddOn.Tooltip = AddOn:NewModule("Tooltip","AceTimer-3.0","AceHook-3.0","AceEvent-3.0")
|
|
AddOn.TotemBar = AddOn:NewModule("Totems","AceEvent-3.0")
|
|
AddOn.UnitFrames = AddOn:NewModule("UnitFrames","AceTimer-3.0","AceEvent-3.0","AceHook-3.0")
|
|
AddOn.WorldMap = AddOn:NewModule("WorldMap","AceHook-3.0","AceEvent-3.0","AceTimer-3.0")
|
|
AddOn.MapMarkers = AddOn:NewModule("MapMarkers","AceHook-3.0","AceComm-3.0","AceSerializer-3.0")
|
|
|
|
do
|
|
local a,b,c = '','([%(%)%.%%%+%-%*%?%[%^%$])','%%%1'
|
|
function AddOn:EscapeString(s) return gsub(s,b,c) end
|
|
|
|
local d = {'|[TA].-|[ta]','|c[fF][fF]%x%x%x%x%x%x','|r','^%s+','%s+$'}
|
|
function AddOn:StripString(s, ignoreTextures)
|
|
for i = ignoreTextures and 2 or 1, #d do s = gsub(s,d[i],a) end
|
|
return s
|
|
end
|
|
end
|
|
|
|
do
|
|
DisableAddOn("ElvUI_EverySecondCounts")
|
|
DisableAddOn("ElvUI_FogOfWar")
|
|
DisableAddOn("ElvUI_VisualAuraTimers")
|
|
DisableAddOn("ElvUI_MinimapButtons")
|
|
DisableAddOn("ElvUI_ChannelAlerts")
|
|
end
|
|
|
|
function AddOn:OnInitialize()
|
|
if not ElvCharacterDB then
|
|
ElvCharacterDB = {}
|
|
end
|
|
|
|
self.db = tcopy(self.DF.profile, true)
|
|
self.global = tcopy(self.DF.global, true)
|
|
|
|
if ElvDB then
|
|
if ElvDB.global then
|
|
self:CopyTable(self.global, ElvDB.global)
|
|
end
|
|
|
|
local profileKey
|
|
if ElvDB.profileKeys then
|
|
profileKey = ElvDB.profileKeys[self.myname.." - "..self.myrealm]
|
|
end
|
|
|
|
if profileKey and ElvDB.profiles and ElvDB.profiles[profileKey] then
|
|
self:CopyTable(self.db, ElvDB.profiles[profileKey])
|
|
end
|
|
end
|
|
|
|
self.private = tcopy(self.privateVars.profile, true)
|
|
|
|
if ElvPrivateDB then
|
|
local profileKey
|
|
if ElvPrivateDB.profileKeys then
|
|
profileKey = ElvPrivateDB.profileKeys[self.myname.." - "..self.myrealm]
|
|
end
|
|
|
|
if profileKey and ElvPrivateDB.profiles and ElvPrivateDB.profiles[profileKey] then
|
|
self:CopyTable(self.private, ElvPrivateDB.profiles[profileKey])
|
|
end
|
|
end
|
|
|
|
self.twoPixelsPlease = false
|
|
self.ScanTooltip = CreateFrame("GameTooltip", "ElvUI_ScanTooltip", _G.UIParent, "GameTooltipTemplate")
|
|
self.PixelMode = self.twoPixelsPlease or self.private.general.pixelPerfect -- keep this over `UIScale`
|
|
self:UIScale(true)
|
|
self:UpdateMedia()
|
|
|
|
self:RegisterEvent("UPDATE_FLOATING_CHAT_WINDOWS", "PixelScaleChanged")
|
|
self:RegisterEvent("PLAYER_REGEN_DISABLED")
|
|
self:Contruct_StaticPopups()
|
|
self:InitializeInitialModules()
|
|
|
|
if IsAddOnLoaded("Tukui") then
|
|
self:StaticPopup_Show("TUKUI_ELVUI_INCOMPATIBLE")
|
|
end
|
|
|
|
local GameMenuButton = EscapeMenu:AddButton(self.title, EscapeMenuSection.AddOns, function()
|
|
AddOn:ToggleOptionsUI()
|
|
return true
|
|
end)
|
|
|
|
self.loadedtime = GetTime()
|
|
end
|
|
|
|
local LoadUI = CreateFrame("Frame")
|
|
LoadUI:RegisterEvent("PLAYER_LOGIN")
|
|
LoadUI:SetScript("OnEvent", function()
|
|
AddOn:Initialize()
|
|
end)
|
|
|
|
function AddOn:PLAYER_REGEN_ENABLED()
|
|
self:ToggleOptionsUI()
|
|
self:UnregisterEvent("PLAYER_REGEN_ENABLED")
|
|
end
|
|
|
|
function AddOn:PLAYER_REGEN_DISABLED()
|
|
local err
|
|
|
|
if IsAddOnLoaded("ElvUI_OptionsUI") then
|
|
local ACD = self.Libs.AceConfigDialog
|
|
if ACD and ACD.OpenFrames and ACD.OpenFrames[AddOnName] then
|
|
self:RegisterEvent("PLAYER_REGEN_ENABLED")
|
|
ACD:Close(AddOnName)
|
|
err = true
|
|
end
|
|
end
|
|
|
|
if self.CreatedMovers then
|
|
for name in pairs(self.CreatedMovers) do
|
|
local mover = _G[name]
|
|
if mover and mover:IsShown() then
|
|
mover:Hide()
|
|
err = true
|
|
end
|
|
end
|
|
end
|
|
|
|
if err then
|
|
self:Print(ERR_NOT_IN_COMBAT)
|
|
end
|
|
end
|
|
|
|
function AddOn:ResetProfile()
|
|
local profileKey
|
|
|
|
if ElvPrivateDB.profileKeys then
|
|
profileKey = ElvPrivateDB.profileKeys[self.myname.." - "..self.myrealm]
|
|
|
|
if profileKey and ElvPrivateDB.profiles and ElvPrivateDB.profiles[profileKey] then
|
|
ElvPrivateDB.profiles[profileKey] = nil
|
|
end
|
|
end
|
|
|
|
ElvCharacterDB = nil
|
|
self.data:_ResetProfile()
|
|
ReloadUI()
|
|
end
|
|
|
|
function AddOn:OnProfileReset()
|
|
AddOn:StaticPopup_Show("RESET_PROFILE_PROMPT")
|
|
end
|
|
|
|
function AddOn:ResetConfigSettings()
|
|
AddOn.configSavedPositionTop, AddOn.configSavedPositionLeft = nil, nil
|
|
AddOn.global.general.AceGUI = AddOn:CopyTable({}, AddOn.DF.global.general.AceGUI)
|
|
end
|
|
|
|
function AddOn:GetConfigPosition()
|
|
return AddOn.configSavedPositionTop, AddOn.configSavedPositionLeft
|
|
end
|
|
|
|
function AddOn:GetConfigSize()
|
|
return AddOn.global.general.AceGUI.width, AddOn.global.general.AceGUI.height
|
|
end
|
|
|
|
function AddOn:UpdateConfigSize(reset)
|
|
local frame = self.GUIFrame
|
|
if not frame then return end
|
|
|
|
local maxWidth, maxHeight = self.UIParent:GetSize()
|
|
frame:SetMinResize(600, 500)
|
|
frame:SetMaxResize(maxWidth-50, maxHeight-50)
|
|
|
|
self.Libs.AceConfigDialog:SetDefaultSize(AddOnName, self:GetConfigDefaultSize())
|
|
|
|
local status = frame.obj and frame.obj.status
|
|
if status then
|
|
if reset then
|
|
self:ResetConfigSettings()
|
|
|
|
status.top, status.left = self:GetConfigPosition()
|
|
status.width, status.height = self:GetConfigDefaultSize()
|
|
|
|
frame.obj:ApplyStatus()
|
|
else
|
|
local top, left = self:GetConfigPosition()
|
|
if top and left then
|
|
status.top, status.left = top, left
|
|
|
|
frame.obj:ApplyStatus()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function AddOn:GetConfigDefaultSize()
|
|
local width, height = AddOn:GetConfigSize()
|
|
local maxWidth, maxHeight = AddOn.UIParent:GetSize()
|
|
width, height = min(maxWidth - 50, width), min(maxHeight - 50, height)
|
|
return width, height
|
|
end
|
|
|
|
function AddOn:ConfigStopMovingOrSizing()
|
|
if self.obj and self.obj.status then
|
|
AddOn.configSavedPositionTop, AddOn.configSavedPositionLeft = AddOn:Round(self:GetTop(), 2), AddOn:Round(self:GetLeft(), 2)
|
|
AddOn.global.general.AceGUI.width, AddOn.global.general.AceGUI.height = AddOn:Round(self:GetWidth(), 2), AddOn:Round(self:GetHeight(), 2)
|
|
end
|
|
end
|
|
|
|
local pageNodes = {}
|
|
function AddOn:ToggleOptionsUI(msg)
|
|
if InCombatLockdown() then
|
|
self:Print(ERR_NOT_IN_COMBAT)
|
|
self:RegisterEvent("PLAYER_REGEN_ENABLED")
|
|
return
|
|
end
|
|
|
|
if not IsAddOnLoaded("ElvUI_OptionsUI") then
|
|
local noConfig
|
|
local _, _, _, _, reason = GetAddOnInfo("ElvUI_OptionsUI")
|
|
if reason ~= "MISSING" and reason ~= "DISABLED" then
|
|
self.GUIFrame = false
|
|
LoadAddOn("ElvUI_OptionsUI")
|
|
|
|
--For some reason, GetAddOnInfo reason is "DEMAND_LOADED" even if the addon is disabled.
|
|
--Workaround: Try to load addon and check if it is loaded right after.
|
|
if not IsAddOnLoaded("ElvUI_OptionsUI") then noConfig = true end
|
|
|
|
-- version check elvui options if it's actually enabled
|
|
if (not noConfig) and GetAddOnMetadata("ElvUI_OptionsUI", "Version") ~= "1.10" then
|
|
self:StaticPopup_Show("CLIENT_UPDATE_REQUEST")
|
|
end
|
|
else
|
|
noConfig = true
|
|
end
|
|
|
|
if noConfig then
|
|
self:Print("|cffff0000Error -- Addon 'ElvUI_OptionsUI' not found or is disabled.|r")
|
|
return
|
|
end
|
|
end
|
|
|
|
local ACD = self.Libs.AceConfigDialog
|
|
local ConfigOpen = ACD and ACD.OpenFrames and ACD.OpenFrames[AddOnName]
|
|
|
|
local pages, msgStr
|
|
if msg and msg ~= "" then
|
|
pages = {strsplit(",", msg)}
|
|
msgStr = gsub(msg, ",","\001")
|
|
end
|
|
|
|
local mode = "Close"
|
|
if not ConfigOpen or (pages ~= nil) then
|
|
if pages ~= nil then
|
|
local pageCount, index, mainSel = #pages
|
|
if pageCount > 1 then
|
|
wipe(pageNodes)
|
|
index = 0
|
|
|
|
local main, mainNode, mainSelStr, sub, subNode, subSel
|
|
for i = 1, pageCount do
|
|
if i == 1 then
|
|
main = pages[i] and ACD and ACD.Status and ACD.Status.ElvUI
|
|
mainSel = main and main.status and main.status.groups and main.status.groups.selected
|
|
mainSelStr = mainSel and ("^"..self:EscapeString(mainSel).."\001")
|
|
mainNode = main and main.children and main.children[pages[i]]
|
|
pageNodes[index + 1], pageNodes[index + 2] = main, mainNode
|
|
else
|
|
sub = pages[i] and pageNodes[i] and ((i == pageCount and pageNodes[i]) or pageNodes[i].children[pages[i]])
|
|
subSel = sub and sub.status and sub.status.groups and sub.status.groups.selected
|
|
subNode = (mainSelStr and msgStr:match(mainSelStr..self:EscapeString(pages[i]).."$") and (subSel and subSel == pages[i])) or ((i == pageCount and not subSel) and mainSel and mainSel == msgStr)
|
|
pageNodes[index + 1], pageNodes[index + 2] = sub, subNode
|
|
end
|
|
index = index + 2
|
|
end
|
|
else
|
|
local main = pages[1] and ACD and ACD.Status and ACD.Status.ElvUI
|
|
mainSel = main and main.status and main.status.groups and main.status.groups.selected
|
|
end
|
|
|
|
if ConfigOpen and ((not index and mainSel and mainSel == msg) or (index and pageNodes and pageNodes[index])) then
|
|
mode = "Close"
|
|
else
|
|
mode = "Open"
|
|
end
|
|
else
|
|
mode = "Open"
|
|
end
|
|
end
|
|
|
|
if ACD then
|
|
ACD[mode](ACD, AddOnName)
|
|
end
|
|
|
|
if mode == "Open" then
|
|
ConfigOpen = ACD and ACD.OpenFrames and ACD.OpenFrames[AddOnName]
|
|
if ConfigOpen then
|
|
local frame = ConfigOpen.frame
|
|
if frame and not self.GUIFrame then
|
|
self.GUIFrame = frame
|
|
ElvUIGUIFrame = self.GUIFrame
|
|
|
|
self:UpdateConfigSize()
|
|
hooksecurefunc(frame, "StopMovingOrSizing", AddOn.ConfigStopMovingOrSizing)
|
|
end
|
|
end
|
|
|
|
if ACD and pages then
|
|
ACD:SelectGroup(AddOnName, unpack(pages))
|
|
end
|
|
end
|
|
|
|
GameTooltip:Hide() --Just in case you're mouseovered something and it closes.
|
|
end |