Files
2024-10-28 07:43:26 -07:00

406 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")
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()
end, nil, true)
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